From 184e85da8420d7c4739b0fd9fe867cf4d505dcf9 Mon Sep 17 00:00:00 2001 From: lipnggao Date: Thu, 21 Sep 2023 14:49:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=98=85=E8=AF=BB=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/novelReading/novelReading.vue | 362 +- uni_modules/yingbing-ReadPage/changelog.md | 40 + .../components/modules/battery.vue | 5 +- .../components/modules/computed/computed.css | 14 + .../components/modules/computed/computed.js | 287 +- .../components/modules/flip/bindingx.js | 250 -- .../components/modules/flip/flip.css | 66 +- .../components/modules/flip/flip.js | 110 +- .../components/modules/flip/flip.vue | 569 ---- .../components/modules/flip/flip.wxs | 208 -- .../components/modules/richtext.vue | 2 +- .../components/modules/scroll/scroll.js | 18 +- .../yingbing-ReadPage/yingbing-ReadPage.vue | 537 +-- uni_modules/yingbing-ReadPage/package.json | 6 +- uni_modules/yingbing-ReadPage/readme.md | 160 +- uni_modules/yingbing-flip/changelog.md | 10 + .../yingbing-flip/components/modules/flip.wxs | 367 ++ .../components/modules/flip_bindingx.js | 546 +++ .../yingbing-flip/yingbing-flip.vue | 420 +++ uni_modules/yingbing-flip/js_sdk/util.js | 446 +++ uni_modules/yingbing-flip/package.json | 81 + uni_modules/yingbing-flip/readme.md | 344 ++ unpackage/dist/dev/app-plus/app-service.js | 2718 ++++++++------- unpackage/dist/dev/app-plus/app-view.js | 2952 ++++++++++------- 24 files changed, 6549 insertions(+), 3969 deletions(-) create mode 100644 uni_modules/yingbing-ReadPage/components/modules/computed/computed.css delete mode 100644 uni_modules/yingbing-ReadPage/components/modules/flip/bindingx.js delete mode 100644 uni_modules/yingbing-ReadPage/components/modules/flip/flip.vue delete mode 100644 uni_modules/yingbing-ReadPage/components/modules/flip/flip.wxs create mode 100644 uni_modules/yingbing-flip/changelog.md create mode 100644 uni_modules/yingbing-flip/components/modules/flip.wxs create mode 100644 uni_modules/yingbing-flip/components/modules/flip_bindingx.js create mode 100644 uni_modules/yingbing-flip/components/yingbing-flip/yingbing-flip.vue create mode 100644 uni_modules/yingbing-flip/js_sdk/util.js create mode 100644 uni_modules/yingbing-flip/package.json create mode 100644 uni_modules/yingbing-flip/readme.md diff --git a/pages/novelReading/novelReading.vue b/pages/novelReading/novelReading.vue index fd98adb..8b0e8c6 100644 --- a/pages/novelReading/novelReading.vue +++ b/pages/novelReading/novelReading.vue @@ -12,33 +12,29 @@ :line-height="defaultCharactersLineHeight" :color="novelContentColor" :bg-color="bodyReadingBg" :slide="20" :enablePreload="false" @loadmore="loadmoreContent" @preload="preloadContent" @change="currentChange" @setCatalog="setCatalog" @clickme="clickme" @clickher="clickher" - @clickTo="handelShowStepUp" :clickOption="{width:200,height: 400,left:'auto',top:'auto'}"> + @clickTo="handelShowStepUp" :clickOption="{width:200,height: 400,left:'auto',top:'auto'}" + @handelPurchaseFull="handelPurchaseFull"> + - - - - - - - 目录 - - - - - - 书城 - - - - - - 设置 - - - @@ -52,7 +48,26 @@ @tap="nextChapter">下一章 - + + + + + + 目录 + + + + + + 书城 + + + + + + 设置 + + @@ -103,7 +118,7 @@ - + + @@ -149,6 +164,7 @@ }, data() { return { + token: '', navbarTitle: '小说阅读页面', novelMainTypeColor: '', setUpColorAll: {}, @@ -165,7 +181,6 @@ bodyReadingBg: '', // 底部安全区 // bottomSecureHeight: 0, - tabBarPopupShow: false, readingPopupshow: false, stepUpPopupShow: false, purchaseFullShow: false, @@ -189,7 +204,7 @@ directoryPopupShow: false, // 小说信息 novelReadingContentText: [], - charactersPageType: 'real', + charactersPageType: 'reals', defaultCharactersSize: 28, newCharactersSize: 28, defaultCharactersLineHeight: 20, @@ -211,23 +226,25 @@ this.readChapterid = options.id; }, onShow() { + const token = myGetStorage('token'); + this.token = token; const bookSid = this.booksDirectorySid; - const data = { - sid: bookSid, - } - uni.$u.http.post('/bookdetails', data).then((res) => { - uni.hideLoading(); - if (res.status == 1) { - const info = res.data.info; - const cover = info.cover.includes('http') ? info.cover : `${config.baseUrl}${info.cover}`; - this.bookInfo = { - ...info, - cover - }; - } - }).catch((err) => { - uni.hideLoading(); - }) + // const data = { + // sid: bookSid, + // } + // uni.$u.http.post('/bookdetails', data).then((res) => { + // uni.hideLoading(); + // if (res.status == 1) { + // const info = res.data.info; + // const cover = info.cover.includes('http') ? info.cover : `${config.baseUrl}${info.cover}`; + // this.bookInfo = { + // ...info, + // cover + // }; + // } + // }).catch((err) => { + // uni.hideLoading(); + // }) this.isGetUserRead(); }, methods: { @@ -277,23 +294,23 @@ title: resData.chaptername, isTtitle: resData.title // richTextNodes: `

${res.data.chaptername}


${res.data.novel_content}` - // richTextNodes: `

${res.data.chaptername}


${res.data.novel_content}` }; this.readChapterInfoObj = readChapterInfoObj; - if (readChapterInfoObj.chackpay == 1) { - resolve(readChapterInfoObj); - } else if (readChapterInfoObj.chackpay == 2) { - this.balanceShow = true; - this.balanceTitle = '下一章,付费章节'; - if (isShowLoading) { - this.readChapterFlag = true; - } - } else if (readChapterInfoObj.chackpay == 3) { - this.purchaseFullShow = true; - if (isShowLoading) { - this.readChapterFlag = true; - } - } + resolve(readChapterInfoObj); + // if (readChapterInfoObj.chackpay == 1) { + + // } else if (readChapterInfoObj.chackpay == 2) { + // this.balanceShow = true; + // this.balanceTitle = '下一章,付费章节'; + // if (isShowLoading) { + // this.readChapterFlag = true; + // } + // } else if (readChapterInfoObj.chackpay == 3) { + // this.purchaseFullShow = true; + // if (isShowLoading) { + // this.readChapterFlag = true; + // } + // } } }).catch((err) => { uni.hideLoading(); @@ -303,34 +320,64 @@ }, async loadmoreContent(chapter, callback) { - console.log(chapter, "*****************") const newReadDirectoryActive = this.readDirectoryActive; const newReadChapterLastid = this.readChapterLastid; const newNovelReadingContentText = this.novelReadingContentText; const newReadChapterNextid = this.readChapterNextid; - console.log(newNovelReadingContentText,"newNovelReadingContentText") - // const itemTemp = newNovelReadingContentText.filter((m) => m.chapter == parseInt(chapter + 1)); - // console.log(itemTemp,itemTemp[0].lastid, "itemTempitemTempitemTemp") - if (newReadDirectoryActive != 1) { + console.log(chapter, newReadDirectoryActive, "loadmoreContent") + if (chapter != 1) { if (chapter < newReadDirectoryActive) { - // const readChapterInfoObj = await this.isGetBookInfo(itemTemp[0].lastid); const readChapterInfoObj = await this.isGetBookInfo(newReadChapterLastid); - console.log(readChapterInfoObj, "上一章") this.novelReadingContentText = [...newNovelReadingContentText, readChapterInfoObj]; this.readDirectoryActive = chapter; - // this.readChapterLastid = readChapterInfoObj.lastid; - // this.readChapterNextid = readChapterInfoObj.nextid; - callback('success', readChapterInfoObj) + if (readChapterInfoObj.chackpay == 1) { + callback('success', readChapterInfoObj) + } + const obj = { + ...readChapterInfoObj, + custom, + content: '' + } + console.log(obj, "objobj") + callback('success', obj) } if (chapter > newReadDirectoryActive) { - // const readChapterInfoObj = await this.isGetBookInfo(itemTemp[0].nextid); const readChapterInfoObj = await this.isGetBookInfo(newReadChapterNextid); - console.log(readChapterInfoObj, "下一章") this.novelReadingContentText = [readChapterInfoObj, ...newNovelReadingContentText]; this.readDirectoryActive = chapter; - // this.readChapterLastid = readChapterInfoObj.lastid; - // this.readChapterNextid = readChapterInfoObj.nextid; - callback('success', readChapterInfoObj) + if (readChapterInfoObj.chackpay == 1) { + callback('success', readChapterInfoObj) + } + if (readChapterInfoObj.chackpay == 2) { + const novelContentColor = this.novelContentColor; + const newCharactersSize = this.newCharactersSize; + const bodyReadingBg = this.bodyReadingBg; + // + const custom = [`slot:test`] + // const custom = [ + // `
+ //
${readChapterInfoObj.content}
+ //
+ //
+ //
+ // 付费章节,需要购买。${readChapterInfoObj.price}书币
+ //
+ //
需要全本购买
+ //
+ //
+ //
` + // ] + const obj = { + ...readChapterInfoObj, + custom, + content: '' + } + console.log(obj, "objobj") + callback('success', obj) + } + } } }, @@ -341,19 +388,30 @@ this.readChapterLastid = itemTemp[0].lastid; this.readChapterNextid = itemTemp[0].nextid; }, - previousChapter() { - const readChapterLastid = this.readChapterLastid - if (!readChapterLastid) { + async previousChapter() { + const newReadDirectoryActive = this.readDirectoryActive; + const newReadChapterLastid = this.readChapterLastid; + const newNovelReadingContentText = this.novelReadingContentText; + if (!newReadChapterLastid) { uni.showToast({ icon: 'none', title: "已经是第一章了" }) return } - this.isGetBookInfo(readChapterLastid, 'previousChapter'); + const readChapterInfoObj = await this.isGetBookInfo(newReadChapterLastid); + this.novelReadingContentText = [readChapterInfoObj]; + this.$refs.yingbingReadPage.init({ + contents: [readChapterInfoObj], + start: 0, + currentChapter: newReadDirectoryActive - 1 + }) + this.readDirectoryActive = newReadDirectoryActive - 1; }, - nextChapter() { + async nextChapter() { + const newReadDirectoryActive = this.readDirectoryActive; const readChapterNextid = this.readChapterNextid; + const newNovelReadingContentText = this.novelReadingContentText; if (!readChapterNextid) { uni.showToast({ icon: 'none', @@ -361,11 +419,17 @@ }) return } - this.isGetBookInfo(readChapterNextid, 'nextChapter'); + const readChapterInfoObj = await this.isGetBookInfo(readChapterNextid); + this.novelReadingContentText = [readChapterInfoObj]; + this.$refs.yingbingReadPage.init({ + contents: [readChapterInfoObj], + start: 0, + currentChapter: newReadDirectoryActive + 1 + }) + this.readDirectoryActive = newReadDirectoryActive + 1; }, handelDirectoryItem(row) {}, handelShowStepUp() { - this.tabBarPopupShow = !this.tabBarPopupShow; this.readingPopupshow = !this.readingPopupshow; this.stepUpPopupShow = false; }, @@ -377,6 +441,13 @@ url: `/pages/bookRecommendList/bookRecommendList?sid=${readChapterInfoObj.sid}&t=${readChapterInfoObj.title}&c=${readDirectoryActive}` }) }, + toPathLogin() { + const readChapterInfoObj = this.readChapterInfoObj; + const readDirectoryActive = this.readDirectoryActive; + uni.navigateTo({ + url: `/pages/login/login?sid=${readChapterInfoObj.sid}&t=${readChapterInfoObj.title}&c=${readDirectoryActive}` + }) + }, directoryPopupClose() { // this.directoryPopupShow = false; // const readChapterInfoObj = this.readChapterInfoObj; @@ -545,30 +616,6 @@ }) } }, - onPullDownRefresh() { - // const isReadDirectoryActive = this.readDirectoryActive; - // if(isReadDirectoryActive == 0) { - // uni.showToast({ - // icon:'none', - // title:"已经是第一章了" - // }) - // uni.stopPullDownRefresh() - // return - // } - // const readDirectoryActive = isReadDirectoryActive- 1; - // const novelReadingContentText = this.myData[readDirectoryActive]; - // this.novelReadingContentText = [novelReadingContentText, ...this.novelReadingContentText]; - // // setTimeout(() => { - // this.computeRichText = this.myData[readDirectoryActive].content; - // // this.readDirectoryActive = readDirectoryActive; - // const query = uni.createSelectorQuery().in(this); - // this.$nextTick(() => { - // query.select(`#compute_rich_text`).boundingClientRect((data) => { - // this.isScrollTop = parseInt(data.height) - 30; - // }).exec(); - // }); - // uni.stopPullDownRefresh() - }, created() { const novelMainObj = myGetStorage('novelMainObj') || '{}'; const novelMainTypeColor = JSON.parse(novelMainObj).novelMainTypeColor || 'F3EFE9'; @@ -581,17 +628,6 @@ this.novelMainTypeColor = novelMainTypeColor; this.newCharactersSize = JSON.parse(novelMainObj).charactersSize || 28; this.bodyReadingHeight = screenHeight - statusBarHeight - devicePixelRatio * 22; - // 不需要 - // this.scrollReadingHeight = screenHeight - statusBarHeight - devicePixelRatio * 38; - // this.scrollReadingHeight = windowHeight - (screenWidth / 375) * 54; - // // #ifdef APP-PLUS - // this.directoryPopupHeight = screenHeight - statusBarHeight; - // // #endif - // // #ifdef H5 || MP-WEIXIN - // this.directoryPopupHeight = screenHeight - statusBarHeight - devicePixelRatio * 22; - // // #endif - - // this.bottomSecureHeight = screenHeight - windowHeight; this.setUpColorAll = setUpReadingColorAll; this.barPopupIcon = { 'F3EFE9': { @@ -631,6 +667,96 @@ margin-top: 40rpx; } + + /deep/.balance_con { + width: 100%; + height: 100%; + overflow: hidden; + position: relative; + + + .balance_con_rich_text { + width: 100%; + height: 80%; + line-height: 2; + overflow: hidden; + // text-overflow: ellipsis; + // display: -webkit-box; + // -webkit-line-clamp: 10; + // -webkit-box-orient: vertical; + } + + .balance_recharge_option { + position: fixed; + bottom: 0; + left: 0; + width: 414px; + height: 560rpx; + // box-shadow: 0 0 8rpx rgba(0, 0, 0, 0.2); + background: rgba(243, 239, 233, 0.7); + filter: blur(10px); + // user-select: none; + // opacity: 0.6; + // background: #fff; + // background-image: linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.6) 80%); + } + + // .balance_recharge_option::after { + // position: absolute; + // top: 0; + // left: 0; + // width: 100%; + // height: 100%; + // content: ''; + // display: block; + + // } + + .balance_recharge { + // display: flex; + // flex-direction: column; + // justify-content: center; + // align-items: center; + position: fixed; + bottom: 0rpx; + left: 0; + width: 100%; + box-shadow: 0 0 8rpx rgba(0, 0, 0, 0.2); + height: 360rpx; + border-radius: 24rpx 24rpx 0 0; + padding: 32rpx; + box-sizing: border-box; + + // background-image: linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, rgb(255, 255, 255) 80%); + // background: rgba(255, 255, 255, 0.2); + // filter: blur(5px); + // user-select: none; + // box-shadow: 0 -20rpx 20rpx rgba(0, 0, 0, 0.2); + .balance_tips { + font-size: 30rpx; + } + + .balance_btn_all { + // display: flex; + // justify-content: center; + // align-items: center; + margin-top: 32rpx; + + .purchaseFull_popup_btn { + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 84rpx; + font-size: 30rpx; + color: #fff; + background: linear-gradient(to top, #FBA676, #E95E32); + border-radius: 24rpx; + } + } + } + } + .novelReading_content::v-deep.u-navbar__content__title { font-size: 30rpx; } diff --git a/uni_modules/yingbing-ReadPage/changelog.md b/uni_modules/yingbing-ReadPage/changelog.md index 07c531b..d7ddc92 100644 --- a/uni_modules/yingbing-ReadPage/changelog.md +++ b/uni_modules/yingbing-ReadPage/changelog.md @@ -1,3 +1,43 @@ +## 1.5.9(2023-09-01) +* 修复滚动模式下计算滚动位置异常的问题 +## 1.5.8(2023-08-23) +* 修复APP-VUE翻页翻往下一章时可能会出现的undefined +## 1.5.7(2023-08-21) +* 增加split属性,用于分隔字符串排版,适用于英文小说 +* measureSize属性中将英文字母大小拆分成小写英文字母和大写英文字母大小 +## 1.5.6(2023-07-24) +* 解决bgColor属性无效的问题 +## 1.5.5(2023-07-22) +* 请注意此次更新将翻页功能抽出来,插件本身只有滚动阅读功能,如果需要翻页功能请下载新插件好用翻页组件配合使用,下载地址看使用介绍 +* 此次更新未更新新功能,不想多下载插件的朋友可以不更新 +## 1.5.4(2023-07-10) +* 增加firstTipUnable、lastTipUnable属性控制第一页提示页和最后一页提示页的显示 +## 1.5.3(2023-07-08) +* 自定义插槽添加作用域插槽,可以获取当前页信息,用于动态绑定内容(不支持微信小程序) +## 1.5.2(2023-07-07) +* 增加firstTip,lastTip属性自定义第一页和最后一页提示文字 +* 增加top、bottom插槽,自定义第一页和最后一页的页面 +## 1.5.1(2023-07-07) +* 新增unableClickPage属性控制点击左右2侧翻页 +## 1.5.0(2023-06-20) +* 修复微信小程序报错的问题 +## 1.4.9(2023-06-14) +* 修复向前翻页页面抖动的问题 +* 优化loadmore事件返回回调为fail或者timeout时的显示 +* 优化change事件,不再强制传contents +## 1.4.8(2023-06-12) +* 修复h5,APP-VUE自定义页面添加点击事件无法点击的问题 +## 1.4.7(2023-06-07) +* 优化h5电量显示,避免报错 +## 1.4.6(2023-06-07) +* 新增自动翻页功能 +* 优化页面刷新逻辑,减少报错 +## 1.4.5(2023-05-27) +* 添加字符宽度自动测量功能,减少排版错误 +* 新增measureSize属性,用于自定义字符宽度 +## 1.4.4(2023-05-26) +* 翻页模式添加touchcancel事件 +* 为兼容IOS空格计算宽度增加1px ## 1.4.3(2023-05-25) * 新增fontFamily属性设置字体名称 * 新增fontFace属性添加自定义字体 diff --git a/uni_modules/yingbing-ReadPage/components/modules/battery.vue b/uni_modules/yingbing-ReadPage/components/modules/battery.vue index 784fb93..c8f3001 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/battery.vue +++ b/uni_modules/yingbing-ReadPage/components/modules/battery.vue @@ -34,13 +34,14 @@ } }, // #endif - mounted () { + created () { this.getBattery() }, methods: { getBattery () { // #ifdef H5 - window.navigator.getBattery().then((res) => { + //window.navigator.getBattery只能在安全环境下(比如:https file:///url)使用,判断一下避免报错 + window.navigator.getBattery && window.navigator.getBattery().then((res) => { // 电池电量在0到1之间,因此我们将其乘以100得出百分比 this.value = res.level * 54 }); diff --git a/uni_modules/yingbing-ReadPage/components/modules/computed/computed.css b/uni_modules/yingbing-ReadPage/components/modules/computed/computed.css new file mode 100644 index 0000000..bf38899 --- /dev/null +++ b/uni_modules/yingbing-ReadPage/components/modules/computed/computed.css @@ -0,0 +1,14 @@ +.computed { + position: fixed; + top: -1000rpx; + left: 0; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + flex-wrap: wrap; +} +.computed-text { + font-size: 20px; + flex-shrink: 0; +} \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/computed/computed.js b/uni_modules/yingbing-ReadPage/components/modules/computed/computed.js index 1f150d7..e9dd35c 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/computed/computed.js +++ b/uni_modules/yingbing-ReadPage/components/modules/computed/computed.js @@ -1,8 +1,22 @@ import Util from '../../../js_sdk/util.js' export default { + props: { + measureSize: { + type: Object, + default () { + return new Object + } + } + }, data () { return { - computedResolve: null + computedResolve: null, + chineseSize: 0, + spaceSize: 0, + lowerSize: 0, + upperSize: 0, + numberSize: 0, + specialSize: 0 } }, methods: { @@ -49,29 +63,62 @@ export default { text = new String(text); text = text.split(''); let width = 0; - text.forEach(function(item) { - if (/[a-zA-Z]/.test(item)) { - width += 7; - } else if (/[0-9]/.test(item)) { - width += 5.5; - } else if (/\./.test(item)) { - width += 2.7; - } else if (/-/.test(item)) { - width += 3.25; + text.forEach((item) => { + if (/[a-z]/.test(item)) { + width += this.measureSize.lower || this.lowerSize || 7 + } else if ( /[A-Z]/.test(item) ) { + width += this.measureSize.upper || this.upperSize || 7 + } else if (/[0-9]/.test(item)) { + width += this.measureSize.number || this.numberSize || 5.5 } else if (/[\u4e00-\u9fa5]/.test(item)) { //中文匹配 - width += 10; - } else if (/\(|\)/.test(item)) { - width += 3.73; + width += this.measureSize.chinese || this.chineseSize || 10 } else if (/\s/.test(item)) { - width += 2.5; + width += this.measureSize.space || this.spaceSize || 3.5 } else if (/[`!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/.test(item)) { - width += 8; + width += this.measureSize.special || this.specialSize || 8 } else { - width += 10; + width += this.measureSize.other || this.chineseSize || 10 } }); return width * fontSize / 10; }, + getComputedTextSize (selector, el) { + let arr = [] + arr.push(Util.getRect('.computed-text-chinese', this.$refs.computedTextChinese, this)) + arr.push(Util.getRect('.computed-text-space', this.$refs.computedTextSpace, this)) + arr.push(Util.getRect('.computed-text-lower', this.$refs.computedTextLower, this)) + arr.push(Util.getRect('.computed-text-upper', this.$refs.computedTextUpper, this)) + arr.push(Util.getRect('.computed-text-number', this.$refs.computedTextNumber, this)) + arr.push(Util.getRect('.computed-text-special', this.$refs.computedTextSpecial, this)) + Promise.all(arr).then(ress => { + ress.forEach((res, key) => { + if ( key == 0 ) { + this.chineseSize = res.width * (10 / 20) + } + if ( key == 1 ) { + this.spaceSize = res.width * (10 / 20) + } + if ( key == 2 ) { + this.lowerSize = res.width * (10 / 20) + } + if ( key == 3 ) { + this.upperSize = res.width * (10 / 20) + } + if ( key == 4 ) { + this.numberSize = res.width * (10 / 20) + } + if ( key == 5 ) { + this.specialSize = res.width * (10 / 20) + } + // console.log('chineseSize', this.chineseSize); + // console.log('spaceSize', this.spaceSize); + // console.log('lowerSize', this.lowerSize); + // console.log('upperSize', this.upperSize); + // console.log('numberSize', this.numberSize); + // console.log('specialSize', this.specialSize); + }) + }) + }, async computedText (data, start) { let rect = await this.getRect() let viewWidth = rect.width - (this.options.slide * 2) @@ -91,32 +138,41 @@ export default { text: [] } let length = 0; - let contentSync = data.content.substr(start); + let contentSync = data.content.substr(start).replace(/\t/g, ' ').replace(/ /g, ' '); let lastIndex = 0; while ( (pageHeight + this.options.fontSize + this.options.lineHeight) <= viewHeight ) { strs.push(''); let lineWidth = 0; + let charText = '' for ( let i = lastIndex; i < contentSync.length; i++ ) { - if ( JSON.stringify(contentSync[i]) == JSON.stringify('\r') || JSON.stringify(contentSync[i]) == JSON.stringify('\n') ) { - length += 1 + const char = contentSync.charAt(i) + if ( JSON.stringify(char) == JSON.stringify('\r') || JSON.stringify(char) == JSON.stringify('\n') ) { + lineWidth += this.measureText(charText, this.options.fontSize); + if ( lineWidth >= viewWidth ) { + lastIndex = i - charText.length+ 1; + break; + } + strs[strs.length - 1] += charText + length += charText.length + 1 page.end = page.start + length; lastIndex = i + 1; break; } - lineWidth += JSON.stringify(contentSync[i]) == JSON.stringify('\t') ? 0 : this.measureText(contentSync[i], this.options.fontSize); - if ( lineWidth >= viewWidth ) { - lastIndex = i; - break; - } else { - if ( JSON.stringify(contentSync[i]) != JSON.stringify('\t') ) { - strs[strs.length - 1] += contentSync[i].replace(' ', ' ') - length += 1 - page.end = page.start + length + charText += char + if ( !this.split || char == this.split ) { + lineWidth += this.measureText(charText, this.options.fontSize); + if ( lineWidth >= viewWidth ) { + lastIndex = i - charText.length+ 1; + break; } + strs[strs.length - 1] += charText + length += charText.length + page.end = page.start + length + charText = '' } } pageHeight += this.options.fontSize + this.options.lineHeight; - if ( page.end >= data.content.replace(/\t/g, '').length - 1 ) { + if ( page.end >= data.content.length - 1 ) { page.isLastPage = true; break; } @@ -188,22 +244,48 @@ export default { arr = arr.concat(pages) if (i == contents.length - 1) { if ( this.options.pageType != 'scroll' ) { - arr.unshift({ - title: contents[0].title || '', - chapter: contents[0].chapter, - type: contents[0].isStart ? 'top' : 'prevLoading', - dataId: arr[0].dataId - 1, - start: 0, - end: 0 - }) - arr.push({ - title: item.title || '', - chapter: item.chapter, - type: item.isEnd ? 'bottom' : 'nextLoading', - dataId: arr[arr.length - 1].dataId + 1, - start: 0, - end: 0 - }) + if ( !this.firstTipUnable ) { + arr.unshift({ + title: contents[0].title || '', + chapter: contents[0].chapter, + type: contents[0].isStart ? 'top' : 'loading', + direction: 'prev', + dataId: arr[0].dataId - 1, + start: 0, + end: 0 + }) + } else if ( !contents[0].isStart ) { + arr.unshift({ + title: contents[0].title || '', + chapter: contents[0].chapter, + type: 'loading', + direction: 'prev', + dataId: arr[0].dataId - 1, + start: 0, + end: 0 + }) + } + if ( !this.lastTipUnable ) { + arr.push({ + title: item.title || '', + chapter: item.chapter, + type: item.isEnd ? 'bottom' : 'loading', + direction: 'next', + dataId: arr[arr.length - 1].dataId + 1, + start: 0, + end: 0 + }) + } else if ( !contents[0].isEnd ) { + arr.push({ + title: item.title || '', + chapter: item.chapter, + type: 'loading', + direction: 'next', + dataId: arr[arr.length - 1].dataId + 1, + start: 0, + end: 0 + }) + } } this.pages = arr if ( this.options.pageType == 'scroll' ) { @@ -211,7 +293,8 @@ export default { } this.$nextTick(() => { if ( this.options.pageType != 'scroll' ) { - this.onChange(this.currentDataId); + this.$refs.flip.refresh() + this.handleFlipChange(this.currentDataId); } else { setTimeout(() => { Util.getRect('#scroll-item_' + this.currentDataId, Util.getRefs(this, 'scrollItem_' + this.currentDataId, 0), this).then(rect => { @@ -235,41 +318,69 @@ export default { computedPage(e) { this.computedChapter(e.content).then((pages) => { let arr = []; - let newPages = []; const pagesSync = e.type == 'prev' ? pages.concat(this.pages) : this.pages.concat(pages); - pagesSync.forEach(item => { - if (arr.indexOf(item.chapter) == -1) arr.push(item.chapter) - }) - if (arr.length > 3) { - let reChapter = e.type == 'prev' ? pagesSync[pagesSync.length - 1].chapter : pagesSync[0].chapter; - newPages = pagesSync.filter(item => item.chapter != reChapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot')); - } else { - newPages = pagesSync.filter(item => (item.type == 'text' || item.type == 'custom' || item.type == 'slot')); - } + let newPages = pagesSync.filter(item => (item.type == 'text' || item.type == 'custom' || item.type == 'slot')) + // pagesSync.forEach(item => { + // if (arr.indexOf(item.chapter) == -1) arr.push(item.chapter) + // }) + // if (arr.length > 3) { + // let reChapter = e.type == 'prev' ? pagesSync[pagesSync.length - 1].chapter : pagesSync[0].chapter; + // newPages = pagesSync.filter(item => item.chapter != reChapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot')); + // } else { + // newPages = pagesSync.filter(item => (item.type == 'text' || item.type == 'custom' || item.type == 'slot')); + // } if ( this.options.pageType != 'scroll' ) { const prevIndex = this.contents.findIndex(content => content.chapter == newPages[0].chapter); const nextIndex = this.contents.findIndex(content => content.chapter == newPages[newPages.length - 1].chapter); - newPages.unshift({ - title: this.contents[prevIndex].title || '', - chapter: this.contents[prevIndex].chapter, - type: this.contents[prevIndex].isStart ? 'top' : 'prevLoading', - dataId: newPages[0].dataId - 1, - start: 0, - end: 0 - }) - newPages.push({ - title: this.contents[nextIndex].title || '', - chapter: this.contents[nextIndex].chapter, - type: this.contents[nextIndex].isEnd ? 'bottom' : 'nextLoading', - dataId: newPages[newPages.length - 1].dataId + 1, - start: 0, - end: 0 - }) + if ( !this.firstTipUnable && this.contents[prevIndex].isStart ) { + newPages.unshift({ + title: this.contents[prevIndex].title || '', + chapter: this.contents[prevIndex].chapter, + type: 'top', + direction: 'prev', + dataId: newPages[0].dataId - 1, + start: 0, + end: 0 + }) + } else { + newPages.unshift({ + title: this.contents[prevIndex].title || '', + chapter: this.contents[prevIndex].chapter, + type: 'loading', + direction: 'prev', + dataId: newPages[0].dataId - 1, + start: 0, + end: 0 + }) + } + if ( !this.lastTipUnable && this.contents[nextIndex].isEnd ) { + newPages.push({ + title: this.contents[nextIndex].title || '', + chapter: this.contents[nextIndex].chapter, + type: 'bottom', + direction: 'next', + dataId: newPages[newPages.length - 1].dataId + 1, + start: 0, + end: 0 + }) + } else { + newPages.push({ + title: this.contents[nextIndex].title || '', + chapter: this.contents[nextIndex].chapter, + type: 'loading', + direction: 'next', + dataId: newPages[newPages.length - 1].dataId + 1, + start: 0, + end: 0 + }) + } this.pages = newPages const nowIndex = newPages.findIndex(page => page.dataId == this.currentDataId); if ( nowIndex == -1 ) { this.currentDataId = e.type == 'next' ? pages[0].dataId : pages[pages.length - 1].dataId; - this.onChange(this.currentDataId) + this.handleFlipChange(this.currentDataId) + } else { + this.startAutoplay() } } else { let dataId = e.type == 'prev' ? this.pages[0].dataId : this.pages[this.pages.length-1].dataId @@ -322,7 +433,7 @@ export default { filterPage (pageInfo) { if ( pageInfo && pageInfo.dataId > -1 ) { const nowChapters = this.pages.filter(item => item.chapter == pageInfo.chapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot')) - let currentPage = nowChapters.findIndex(item => item.dataId == pageInfo.dataId) + const currentPage = nowChapters.findIndex(item => item.dataId == pageInfo.dataId) if ( currentPage > -1 ) { return (currentPage + 1) + ' / ' + nowChapters.length } else { @@ -335,32 +446,6 @@ export default { filterDate () { let date = new Date() return Util.zeroize(date.getHours()) + ':' + Util.zeroize(date.getMinutes()) - }, - //翻往上一页 - pagePrev () { - if ( this.options.pageType != 'scroll' ) { - // #ifndef APP-NVUE - this.pagePrevWxs() - // #endif - // #ifdef APP-NVUE - this.pagePrevBinding() - // #endif - } else { - this.scrollPrev() - } - }, - //翻往下一页 - pageNext () { - if ( this.options.pageType != 'scroll' ) { - // #ifndef APP-NVUE - this.pageNextWxs() - // #endif - // #ifdef APP-NVUE - this.pageNextBinding() - // #endif - } else { - this.scrollNext() - } - }, + } } } \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/flip/bindingx.js b/uni_modules/yingbing-ReadPage/components/modules/flip/bindingx.js deleted file mode 100644 index 298b93a..0000000 --- a/uni_modules/yingbing-ReadPage/components/modules/flip/bindingx.js +++ /dev/null @@ -1,250 +0,0 @@ -const Binding = uni.requireNativePlugin('bindingx') -const animation = uni.requireNativePlugin('animation') -import Util from '../../../js_sdk/util.js' -export default { - data () { - return { - disableTouch: false, - isTouch: false, - flipTouchTime: 0, - interval: false, - direction: '' - } - }, - beforeDestroy () { - if ( this.flip_binding ) { - Binding.unbind({ - token: this.flip_binding.token, - eventType: 'pan' - }) - this.flip_binding = null - } - if ( this.flip_animation_binding ) { - Binding.unbind({ - token: this.flip_animation_binding.token, - eventType: 'timing' - }) - this.flip_animation_binding = null - } - }, - methods: { - //翻往上一页 - pagePrevBinding () { - if ( !this.isTouch && !this.disableTouch ) { - this.isTouch = true - this.startX = 0 - this.onFilpTouchend() - } - }, - //翻往下一页 - pageNextBinding () { - if ( !this.isTouch && !this.disableTouch ) { - this.isTouch = true - this.startX = this.viewWidth - this.onFilpTouchend() - } - }, - onFilpTouchstart (event) { - if ( this.isTouch || this.disableTouch ) { - return - } - this.isTouch = true - this.flipTouchTime = 0 - this.interval = true - this.setInterval() - let touch = event.touches[0] - this.startX = touch.pageX - this.startY = touch.pageY - }, - async onFilpTouchmove (event) { - if ( this.isTouch && (this.pageType == 'real' || this.pageType == 'cover') && !this.disableTouch && this.flipTouchTime > 200 ) { - if ( !this.direction ) { - let touch = event.touches[0] - if ( touch.pageX < this.startX ) { - if ( this.nextDataId ) { - this.direction = 'next' - } - } else { - if ( this.prevDataId ) { - this.direction = 'prev' - } - } - } - if ( this.direction ) { - this.disableTouch = true - let currentDataId = this.direction == 'next' ? this.currentDataId : this.prevDataId - let props = [{ - element: Util.getEl(this.$refs['flipItem_' + currentDataId][0]), - property: 'transform.translateX', - expression: `${this.direction == 'next' ? ('x > 0 ? 0 : (x < -' + this.viewWidth + ' ? -' + this.viewWidth + ' : x + 0)') : ('x < 0 ? -' + this.viewWidth + ' : (x > ' + this.viewWidth + ' ? 0 : x-' + this.viewWidth + ')')}` - }] - if ( this.pageType == 'real' ) { - props.push({ - element: Util.getEl(this.$refs['flipItemWrapper_' + currentDataId][0]), - property: 'transform.translateX', - expression: `${this.direction == 'next' ? ('x > 0 ? 0 : (x < -' + this.viewWidth + ' ? ' + this.viewWidth + ' : 0 - x)') : ('x < 0 ? ' + this.viewWidth + ' : (x > ' + this.viewWidth + ' ? 0 : ' + this.viewWidth + '-x)')}` - }) - props.push({ - element: Util.getEl(this.$refs['flipItemBg_' + currentDataId][0]), - property: 'transform.translateX', - expression: `${this.direction == 'next' ? ('x > 0 ? 0 : (x < -' + this.viewWidth + ' ? -' + this.viewWidth + ' : x + 0)') : ('x < 0 ? -' + this.viewWidth + ' : (x > ' + this.viewWidth + ' ? 0 : x-' + this.viewWidth + ')')}` - }) - let rect = await this.getRect(this.$refs['flipItemBg_' + currentDataId][0]) - let height = rect.height / 2; - let maxDeg = height / 5; - props.push({ - element: Util.getEl(this.$refs['flipItemBg_' + currentDataId][0]), - property: 'transform.rotateZ', - expression: `${this.direction == 'next' ? 'y/' + maxDeg : '-(y/' + maxDeg + ')'}` - }) - props.push({ - element: Util.getEl(this.$refs['flipItemShadow_' + currentDataId][0]), - property: 'width', - expression: `${this.direction == 'next' ? 'abs(x) / 2 + 0' : this.viewWidth / 2 + '-abs(x) / 2'}` - }) - } - this.flip_binding = Binding.bind({ - anchor: Util.getEl(this.$refs.yingbingFlip), - eventType: 'pan', - props: props - }, (e) => { - if ((e.state == 'end' || e.state == 'cancel') && this.flip_binding) { - this.clearInterval() - Binding.unbind({ - token: this.flip_binding.token, - eventType: 'pan' - }) - this.flip_binding = null - let value = this.direction == 'next' ? 1 : -1; - if (this.flipTouchTime <= 200) { - let duration = (this.pageType == 'real' || this.pageType == 'cover') ? 200 : 1 - this.pageAnimation(value, -value * this.viewWidth, duration); - } else { - let duration = (this.pageType == 'real' || this.pageType == 'cover') ? 200 : 1 - let deltaX = Binding.getComputedStyle(Util.getEl(this.$refs['flipItem_' + currentDataId][0])).translateX - let late = this.direction == 'next' ? deltaX : this.viewWidth + deltaX - if (Math.abs(late) >= this.viewWidth / 4) { - this.pageAnimation(value, -value * this.viewWidth, duration) - } else { - let value = this.direction == 'next' ? 1 : -1; - this.pageAnimation(value, 0, duration); - } - } - } - }) - } else { - this.resetPageBinding() - } - } - }, - onFilpTouchend () { - if ( this.isTouch && !this.disableTouch ) { - this.disableTouch = true - this.clearInterval() - if ( this.flipTouchTime <= 200 ) { - if ( !this.direction ) { - if (this.startX > (this.viewWidth / 4) * 3) { - if ( this.nextDataId ) { - this.direction = 'next' - } - } - if (this.startX < (this.viewWidth / 4)) { - if ( this.prevDataId ) { - this.direction = 'prev' - } - } - } - if ( this.direction ) { - let duration = (this.pageType == 'real' || this.pageType == 'cover') ? 200 : 1 - let value = this.direction == 'next' ? 1 : -1; - this.pageAnimation(value, -value * this.viewWidth, duration); - } else { - this.resetPageBinding() - } - } else { - this.resetPageBinding() - } - } - }, - getRect (el) { - return new Promise(resolve => { - uni.requireNativePlugin('dom').getComponentRect(el, res => { - resolve(res.size) - }) - }) - }, - setInterval () { - this.flipTouchTimer = setTimeout(() => { - this.flipTouchTime += 10 - if ( this.interval ) { - this.setInterval() - } - }, 10) - }, - clearInterval () { - this.interval = false - if ( this.flipTouchTimer ) { - clearTimeout(this.flipTouchTimer) - this.flipTouchTimer = null - } - }, - pageAnimation (value, offset, duration) { - let currentDataId = this.direction == 'next' ? this.currentDataId : this.prevDataId - let late = this.direction == 'next' ? offset : offset - this.viewWidth; - let flipItemTrans = Binding.getComputedStyle(Util.getEl(this.$refs['flipItem_' + currentDataId][0])).translateX - let props = [{ - element: Util.getEl(this.$refs['flipItem_' + currentDataId][0]), - property: 'transform.translateX', - expression: `linear(t, ${flipItemTrans}, ${late - flipItemTrans}, ${duration})` - }] - if ( this.pageType == 'real' ) { - let flipItemWrapperTrans = Binding.getComputedStyle(Util.getEl(this.$refs['flipItemWrapper_' + currentDataId][0])).translateX - props.push({ - element: Util.getEl(this.$refs['flipItemWrapper_' + currentDataId][0]), - property: 'transform.translateX', - expression: `linear(t, ${flipItemWrapperTrans}, ${-late - flipItemWrapperTrans}, ${duration})` - }) - let flipItemBgTrans = Binding.getComputedStyle(Util.getEl(this.$refs['flipItemBg_' + currentDataId][0])).translateX - props.push({ - element: Util.getEl(this.$refs['flipItemBg_' + currentDataId][0]), - property: 'transform.translateX', - expression: `linear(t, ${flipItemBgTrans}, ${late - flipItemBgTrans}, ${duration})` - }) - let flipItemShadowWidth = this.flipTouchTime <= 200 && this.direction == 'prev' ? this.viewWidth : Binding.getComputedStyle(Util.getEl(this.$refs['flipItemShadow_' + currentDataId][0])).width - props.push({ - element: Util.getEl(this.$refs['flipItemShadow_' + currentDataId][0]), - property: 'width', - expression: `linear(t, ${flipItemShadowWidth}, ${-late - flipItemShadowWidth}, ${duration})` - }) - } - this.flip_animation_binding = Binding.bind({ - eventType: 'timing', - exitExpression: 't>' + duration, - props: props - }, (e) => { - if (e.state == 'exit' && this.flip_animation_binding && e.t > duration) { - Binding.unbind({ - token: this.flip_animation_binding.token, - eventType: 'timing' - }) - this.flip_animation_binding = null - if ( Math.abs(offset) > 0 ) { - this.onChange(value > 0 ? this.nextDataId : this.prevDataId) - } - this.resetPageBinding(); - } - }) - }, - resetPageBinding () { - this.direction = '' - this.flipTouchTime = 0 - this.startX = 0 - this.startY = 0 - this.$nextTick(function () { - this.isTouch = false - this.disableTouch = false - }) - } - } -} - \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.css b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.css index 659595d..9835ac8 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.css +++ b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.css @@ -5,44 +5,17 @@ right: 0; bottom: 0; } -.yingbing-flip { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - /* #ifndef APP-NVUE */ - box-sizing: border-box; - overflow: hidden; - display: flex; - flex-direction: column; - /* #endif */ -} -.flip-item { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - /* #ifndef APP-NVUE */ - box-sizing: border-box; - overflow: hidden; - display: flex; - flex-direction: column; - /* #endif */ -} .flip-item-wrapper { + /* #ifndef APP-NVUE */ + display: flex; + flex-direction: column; + box-sizing: border-box; + /* #endif */ position: absolute; top: 0; left: 0; - bottom: 0; right: 0; - /* #ifndef APP-NVUE */ - box-sizing: border-box; - overflow: hidden; - display: flex; - flex-direction: column; - /* #endif */ + bottom: 0; } .flip-item-header { /* #ifndef APP-NVUE */ @@ -55,7 +28,7 @@ overflow: hidden; } .flip-item-header-text { - font-size: 30rpx; + font-size: 24rpx; opacity: .4; font-weight: bold; /* #ifdef APP-NVUE */ @@ -88,13 +61,13 @@ font-weight: bold; } .flip-item-content { - flex: 1; /* #ifndef APP-NVUE */ box-sizing: border-box; overflow: hidden; display: flex; flex-direction: column; /* #endif */ + flex: 1; } .flip-item-text { /* #ifndef APP-NVUE */ @@ -115,20 +88,11 @@ align-items: center; justify-content: center; } -.flip-item-bg { - position: absolute; - /* #ifdef APP-NVUE */ - box-shadow: 0 20rpx 20rpx rgba(0,0,0,0.2); - /* #endif */ +.flip-loading-text { + font-size: 20px; } -.flip-item-shadow { - position: absolute; - width: 0; - top: 0; - bottom: 0; - right: 0; - /* #ifdef APP-NVUE */ - background-image: linear-gradient(to right, rgba(255,255,255, 0), rgba(0,0,0,.5)); - opacity: 0.5; - /* #endif */ -} \ No newline at end of file +/* #ifndef APP-NVUE */ +view, image, input, scroll-view, swiper, swiper-item, text, textarea, video { + position: static; +} +/* #endif */ \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.js b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.js index 58e53cf..26aaedf 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.js +++ b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.js @@ -1,33 +1,14 @@ import Util from '../../../js_sdk/util.js' -// #ifdef APP-NVUE -import FlipBindingx from './bindingx.js' -// #endif export default { - // #ifdef APP-NVUE - mixins: [FlipBindingx], - // #endif computed: { - dataReverse () { - let data = JSON.parse(JSON.stringify(this.pages)) - return data.reverse() - }, current () { - return this.dataReverse.findIndex(item => item.dataId == this.currentDataId) + return this.pages.findIndex(item => item.dataId == this.currentDataId) }, prevDataId () { - return this.dataReverse[this.current + 1] && this.dataReverse[this.current + 1].dataId + return this.pages[this.current - 1] && this.pages[this.current - 1].dataId }, nextDataId () { - return this.dataReverse[this.current - 1] && this.dataReverse[this.current - 1].dataId - }, - flipProp () { - return { - prevDataId: this.prevDataId, - nextDataId: this.nextDataId, - currentDataId: this.currentDataId, - pageType: this.options.pageType, - pageTo: this.pageTo - } + return this.pages[this.current + 1] && this.pages[this.current + 1].dataId } }, data() { @@ -35,52 +16,27 @@ export default { currentDataId: -1, isShow: false, viewWidth: 0, - viewHeight: 0, - pageTo: 0, - moreLoading: false, - initLoading: true, - loadingText: '正在加载内容', - loadStatus: 'none', - loadChapter: -1, - loadValue: 0 - } - }, - mounted () { - if ( this.pageType != 'scroll' ) { - this.$nextTick(function () { - setTimeout(() => { - this.getViewRect() - }, 50) - }) + moreLoading: false } }, methods: { //翻往上一页 - pagePrevWxs () { - this.pageTo = 0 - this.$nextTick(function(){ - this.pageTo = -1 - }) + pagePrevFlip () { + this.$refs.flip.flipToPrev() }, //翻往下一页 - pageNextWxs () { - this.pageTo = 0 - this.$nextTick(function(){ - this.pageTo = 1 - }) + pageNextFlip () { + this.$refs.flip.flipToNext() }, - reload () { - if ( this.loadStatus == 'fail' || this.loadStatus == 'timeout' ) { - this.initLoading = false - this.loadingText = '正在加载内容' - this.loadStatus = 'none'; - this.loadmore(this.loadChapter, this.loadValue); - this.loadChapter = -1; - this.loadValue = 0; - } + reloadLoadmoreFlip (p) { + let loadIndex = this.pages.findIndex(page => p.dataId == page.dataId) + this.$set(this.pages[loadIndex], 'type', 'loading') + let nextChapter = p.direction == 'next' ? p.chapter + 1 : p.chapter - 1 + this.loadmoreFlip(nextChapter, p.direction == 'next' ? 1 : -1); }, - loadmore (chapter, value) { + loadmoreFlip (chapter, value) { this.$emit('loadmore', chapter, (status, content) => { + this.moreLoading = false; if (status == 'success') { const index = this.contents.findIndex(item => item.chapter == content.chapter) if (index > -1) { @@ -93,33 +49,16 @@ export default { type: value > 0 ? 'next' : 'prev' }); this.preload(chapter) - this.moreLoading = false; - } else if ( status == 'fail' ) { - this.loadStatus = status; - this.loadingText = '请求失败,点击重试' - this.initLoading = true - this.loadChapter = chapter; - this.loadValue = value; } else { - this.loadStatus = status; - this.loadingText = '请求超时,点击重试' - this.initLoading = true - this.loadChapter = chapter; - this.loadValue = value; + let loadIndex = this.pages.findIndex(page => page.type == 'loading' && page.direction == (value > 0 ? 'next' : 'prev')) + this.$set(this.pages[loadIndex], 'type', status) } }) }, - getViewRect () { - return new Promise(resolve => { - Util.getRect('.yingbing-flip', this.$refs.yingbingFlip, this).then(res => { - this.viewWidth = res.width - this.viewHeight = res.height - this.isShow = true - resolve(true) - }) - }) + handleFlipChangeRender (e) { + this.handleFlipChange(e.detail.dataId) }, - onChange(dataId) { + handleFlipChange (dataId) { const value = dataId < this.currentDataId ? -1 : 1 this.currentDataId = dataId const index = this.pages.findIndex(page => page.dataId == dataId); @@ -130,10 +69,9 @@ export default { pageInfo.currentPage = nowChapters.findIndex(item => item.dataId == pageInfo.dataId) + 1 if ( this.contents[contentIndex].title ) pageInfo.title = this.contents[contentIndex].title this.pageInfo = pageInfo - this.$emit('change', pageInfo, this.pages) + this._emitPageInfo(pageInfo, this.pages) const nextType = this.pages[index + value] && this.pages[index + value].type - const loadings = ['nextLoading', 'prevLoading'] - if ( loadings.indexOf(this.pages[index].type) >-1 || loadings.indexOf(nextType) >-1) { + if ( this.pages[index].type == 'loading' || nextType == 'loading') { if (this.moreLoading) return this.moreLoading = true; const loadChapter = this.pages[index].chapter + value; @@ -146,8 +84,10 @@ export default { this.preload(loadChapter) this.moreLoading = false; } else { - this.loadmore(loadChapter, value) + this.loadmoreFlip(loadChapter, value) } + } else { + this.startAutoplay() } } } diff --git a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.vue b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.vue deleted file mode 100644 index 6f2774e..0000000 --- a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.vue +++ /dev/null @@ -1,569 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.wxs b/uni_modules/yingbing-ReadPage/components/modules/flip/flip.wxs deleted file mode 100644 index e15a14a..0000000 --- a/uni_modules/yingbing-ReadPage/components/modules/flip/flip.wxs +++ /dev/null @@ -1,208 +0,0 @@ -function touchstart (event, ins) { - var state = ins.getState() - if ( state.isTouch || state.disableTouch ) { - return - } - state.isTouch = true - state.touchTime = 0 - state.interval = true - setInterval(ins) - var touch = event.touches[0] - state.startX = touch.pageX - state.startY = touch.pageY -} -function touchmove (event, ins) { - event.preventDefault && event.preventDefault() - var state = ins.getState() - if ( state.isTouch && (state.pageType == 'real' || state.pageType == 'cover') && !state.disableTouch ) { - var touch = event.touches[0] - if (state.direction) { - var rect = ins.getBoundingClientRect() - var height = rect.height / 2; - var maxDeg = height / 5; - state.rotate = state.direction == 'next' ? ((touch.pageY - height) / maxDeg) : -((touch.pageY - height) / maxDeg); - state.offset = touch.pageX - state.startX; - if ( (state.offset > 0 && state.direction == 'next') || (state.offset < 0 && state.direction == 'prev') ) { - state.offset = 0 - } - if ( Math.abs(state.offset) <= rect.width ) { - animation(state.offset, 0, ins) - } - } else { - if ( touch.pageX < state.startX ) { - if ( state.nextDataId ) { - state.direction = 'next' - } - } else { - if ( state.prevDataId ) { - state.direction = 'prev' - } - } - } - } -} -function touchend (event, ins) { - var state = ins.getState() - clearInterval(ins) - if ( state.isTouch && !state.disableTouch ) { - var rect = ins.getBoundingClientRect() - if ( !state.direction && state.touchTime <= 200 ) { - //获取点击位置,判断向哪里翻页 - if (state.startX > (rect.width / 4) * 3) { - if ( state.nextDataId ) { - state.direction = 'next' - } - } - if (state.startX < (rect.width / 4)) { - if ( state.prevDataId ) { - state.direction = 'prev' - } - } - } - if (state.direction) { - state.disableTouch = true - if (state.touchTime <= 200) { - var duration = (state.pageType == 'real' || state.pageType == 'cover') ? 200 : 0 - var value = state.direction == 'next' ? 1 : -1; - animation(-value * rect.width, duration, ins); - ins.setTimeout(function () { - reset(-value * rect.width, ins); - ins.callMethod('onChange', value > 0 ? state.nextDataId : state.prevDataId) - }, duration) - } else { - var duration = (state.pageType == 'real' || state.pageType == 'cover') ? 100 : 0 - if (Math.abs(state.offset) >= rect.width / 4) { - var value = state.direction == 'next' ? 1 : -1; - animation(-value * rect.width, duration, ins); - ins.setTimeout(function () { - reset(-value * rect.width, ins); - ins.callMethod('onChange', value > 0 ? state.nextDataId : state.prevDataId) - }, duration) - } else { - animation(0, duration, ins); - ins.setTimeout(function () { - reset(0, ins); - }, duration) - } - } - } else { - reset(0, ins) - } - } -} -function propWatcher (newVal, oldVal, ins) { - if ( oldVal ) { - var state = ins.getState() - state.currentDataId = newVal.currentDataId - state.prevDataId = newVal.prevDataId - state.nextDataId = newVal.nextDataId - state.pageType = newVal.pageType - if (newVal.pageTo != oldVal.pageTo) { - if ( !state.disableTouch ) { - if ( newVal.pageTo == -1 && state.prevDataId ) { - state.isTouch = true - state.startX = 1 - state.touchTime = 0 - state.direction = 'prev' - touchend(null, ins) - } - if ( newVal.pageTo == 1 && state.nextDataId ) { - state.isTouch = true - var rect = ins.getBoundingClientRect() - state.startX = rect.width - state.touchTime = 0 - state.direction = 'next' - touchend(null, ins) - } - } - } - } -} -function setInterval (ins) { - var state = ins.getState() - state.touchTimer = ins.setTimeout(function () { - state.touchTime += 10 - if ( state.interval ) { - setInterval(ins) - } - }, 10) -} -function clearInterval (ins) { - var state = ins.getState() - state.interval = false - if ( state.touchTimer ) { - ins.clearTimeout(state.touchTimer) - state.touchTimer = null - } -} -function reset (offset, ins) { - var state = ins.getState() - var rect = ins.getBoundingClientRect() - if ( state.direction ) { - var late = state.direction == 'next' ? offset : offset - rect.width; - var currentDataId = state.direction == 'next' ? state.currentDataId : state.prevDataId - if ( currentDataId ) { - var draw = function () { - ins.selectComponent('.flip-item_' + currentDataId).setStyle({ - transform: 'translateX(' + late + 'px)', - 'box-shadow': '', - transition: '' - }) - if ( state.pageType == 'real' ) { - ins.selectComponent('.flip-item-bg_' + currentDataId).setStyle({ - transform: 'translateX(' + late + 'px) rotateZ(' + state.rotate + 'deg)', - 'box-shadow': '', - transition: '' - }) - } - ins.selectComponent('.flip-item-shadow_' + currentDataId).setStyle({ - 'box-shadow': '', - transition: '' - }) - } - ins.requestAnimationFrame(draw) - } - } - state.direction = null - state.isTouch = false - state.disableTouch = false - state.offset = 0 - state.touchTime = 0 - state.startX = 0 - state.startY = 0 -} -function animation (offset, duration, ins) { - var state = ins.getState() - var rect = ins.getBoundingClientRect() - var late = state.direction == 'next' ? offset : offset - rect.width; - var currentDataId = state.direction == 'next' ? state.currentDataId : state.prevDataId - var draw = function () { - ins.selectComponent('.flip-item_' + currentDataId).setStyle({ - transform: 'translateX(' + late + 'px)', - 'box-shadow': state.pageType == 'real' ? '0 0 30px 20px rgba(0,0,0,0.4)' : state.pageType == 'cover' ? '0 0 10px 5px rgba(0,0,0,0.3)' : '', - transition: duration > 0 ? 'transform ' + duration + 'ms' : '' - }) - if ( state.pageType == 'real' ) { - ins.selectComponent('.flip-item-wrapper_' + currentDataId).setStyle({ - transform: 'translateX(' + (-late) + 'px)', - transition: duration > 0 ? 'transform ' + duration + 'ms' : '' - }) - ins.selectComponent('.flip-item-bg_' + currentDataId).setStyle({ - transform: 'translateX(' + late + 'px) rotateZ(' + state.rotate + 'deg)', - 'box-shadow': '-5px 0 20px rgba(0,0,0,0.1)', - transition: duration > 0 ? 'transform ' + duration + 'ms, ' + 'boxShadow ' + duration + 'ms' : '' - }) - ins.selectComponent('.flip-item-shadow_' + currentDataId).setStyle({ - 'box-shadow': '0 0 60px 30px rgba(0,0,0,0.4)', - transition: duration > 0 ? 'boxShadow ' + duration + 'ms' : '' - }) - } - } - ins.requestAnimationFrame(draw) -} -module.exports = { - touchstart: touchstart, - touchmove: touchmove, - touchend: touchend, - propWatcher: propWatcher -} \ No newline at end of file diff --git a/uni_modules/yingbing-ReadPage/components/modules/richtext.vue b/uni_modules/yingbing-ReadPage/components/modules/richtext.vue index a3e3eda..f6dd416 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/richtext.vue +++ b/uni_modules/yingbing-ReadPage/components/modules/richtext.vue @@ -76,7 +76,7 @@ }) }, setFontFace () { - this.$refs.webview.evalJS("setFontFace(" + encodeURIComponent(JSON.stringify(this.fontFace)) + ")") + this.$refs.webview && this.$refs.webview.evalJS("setFontFace(" + encodeURIComponent(JSON.stringify(this.fontFace)) + ")") } }, watch: { diff --git a/uni_modules/yingbing-ReadPage/components/modules/scroll/scroll.js b/uni_modules/yingbing-ReadPage/components/modules/scroll/scroll.js index 387d526..31dc787 100644 --- a/uni_modules/yingbing-ReadPage/components/modules/scroll/scroll.js +++ b/uni_modules/yingbing-ReadPage/components/modules/scroll/scroll.js @@ -23,7 +23,7 @@ export default { return } this.scrolling = true - this.$refs.list.scrollTo(this.scrollTop + this.options.fontSize + this.options.lineHeight, true) + this.$refs.list.scrollTo(this.scrollTop + (this.windowHeight / 2), true) this.scrollTimer = setTimeout(() => { this.scrolling = false clearTimeout(this.scrollTimer) @@ -35,14 +35,14 @@ export default { return } this.scrolling = true - this.$refs.list.scrollTo(this.scrollTop - (this.options.fontSize + this.options.lineHeight), true) + this.$refs.list.scrollTo(this.scrollTop - (this.windowHeight / 2), true) this.scrollTimer = setTimeout(() => { this.scrolling = false clearTimeout(this.scrollTimer) this.scrollTimer = null }, 300) }, - onPulldown (callback) { + pulldownScroll (callback) { let contentsIndex = this.contents.findIndex(content => content.chapter == this.pages[0].chapter) if ( this.contents[contentsIndex].isStart ) { callback('end') @@ -64,7 +64,8 @@ export default { this.$refs.list.resetLoadmore() } }, - onLoadmore (callback) { + loadmoreScroll (callback) { + this.stopAutoplay() let contentsIndex = this.contents.findIndex(content => content.chapter == this.pages[this.pages.length - 1].chapter) if ( this.contents[contentsIndex].isEnd ) { callback('end') @@ -103,12 +104,13 @@ export default { }); this.preload(chapter) } - callback && callback('success') + callback && callback(status) }) } }, async scrollEnd(e) { - let rate = Math.floor(e.scrollTop / this.viewHeight) + const size = await this.getRect() + let rate = Math.floor(e.scrollTop / size.height) let maybe = this.pages[rate] ? rate : this.pages.length-1 let top = -1 let pageInfo = null @@ -127,7 +129,8 @@ export default { //刷新当前时间和设备电量 this.scrollDate = this.filterDate() this.$refs.scrollBattery.getBattery() - this.$emit('change', pageInfo, this.pages) + this._emitPageInfo(pageInfo, this.pages) + this.startAutoplay() } }, getScrollItemRect (dataId) { @@ -138,6 +141,7 @@ export default { }) }, onScroll (e) { + this.stopAutoplay() if ( this.options.pageType == 'scroll' ) { this.scrollTop = e.scrollTop if ( this.scrollTimer ) { diff --git a/uni_modules/yingbing-ReadPage/components/yingbing-ReadPage/yingbing-ReadPage.vue b/uni_modules/yingbing-ReadPage/components/yingbing-ReadPage/yingbing-ReadPage.vue index 579e527..3e9cd02 100644 --- a/uni_modules/yingbing-ReadPage/components/yingbing-ReadPage/yingbing-ReadPage.vue +++ b/uni_modules/yingbing-ReadPage/components/yingbing-ReadPage/yingbing-ReadPage.vue @@ -1,152 +1,124 @@ - - + + {{loadstatus == 'fail' ? '加载失败' : '加载超时'}},点击刷新 + + + @@ -275,6 +253,16 @@ ListLoading }, props: { + //自动翻页/滚动 + autoplay: { + type: Boolean, + default: false + }, + //自动翻页/滚动周期 + autoplayTime: { + type: [String, Number], + default: 5000 + }, //字体颜色 color: { type: String, @@ -297,11 +285,34 @@ return new Array } }, + firstTip: { + type: String, + default: '前面已经没有了' + }, + lastTip: { + type: String, + default: '后面已经没有了' + }, + //关闭第一页提示 + firstTipUnable: { + type: Boolean, + default: false + }, + //关闭最后一页提示 + lastTipUnable: { + type: Boolean, + default: false + }, //背景颜色 bgColor: { type: String, default: '#fcd281' }, + //是否关闭点击左右2侧位置翻页 + unableClickPage: { + type: Boolean, + default: false + }, //翻页方式 pageType: { type: String, @@ -352,6 +363,11 @@ type: Boolean, default: true }, + //分隔符 + split: { + type: String, + default: '' + }, //点击事件位置设置 clickOption: { type: Object, @@ -363,7 +379,7 @@ top: 'auto' } } - }, + } }, data () { return { @@ -379,7 +395,11 @@ touchmoveY: 0, touchTime: 0, windowWidth: 0, - windowHeight: 0 + windowHeight: 0, + initLoading: true, + loadstatus: '', + loadchapter: -1, + loadstart: -1 } }, computed: { @@ -388,6 +408,7 @@ }, options () { return { + unableClickPage: this.unableClickPage, pageType: this.pageType, color: this.color, bgColor: this.bgColor, @@ -405,10 +426,8 @@ } }, beforeDestroy () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } + this.clearRefreshTimer() + this.stopAutoplay() }, mounted () { this.$nextTick(function () { @@ -423,6 +442,7 @@ }, methods: { touchstart (e) { + this.stopAutoplay() if ( !this.enableClick ) { return } @@ -449,6 +469,7 @@ this.touchmoveY = touch.pageY; }, touchend (e) { + this.startAutoplay() if ( this.touchInter ) { clearTimeout(this.touchInter); this.touchInter = null @@ -501,11 +522,9 @@ this.$emit('setCatalog', e); }, //初始化 - init (data) { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } + async init (data) { + this.clearRefreshTimer() + await this.getComputedTextSize() if ( !this.noChapter ) { this.contents = data.contents; this.initLoading = true; @@ -519,21 +538,57 @@ }, //重计算 refresh () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null + this.stopAutoplay() + this.clearRefreshTimer() + if ( this.isRefreshing ) { + this.refreshTimer = setTimeout(() => { + this.refresh() + }, 100) + return } + this.isRefreshing = true this.resetPage({ start: this.pageInfo.start, currentChapter: this.pageInfo.chapter }) }, + _emitPageInfo (pageInfo, pages) { + this.isRefreshing = false + this.$emit('change', pageInfo, pages) + }, + _reload () { + this.initLoading = true + if ( this.loadchapter > -1 ) { + this.$emit('loadmore', parseInt(this.loadchapter), (status, content) => { + this.initLoading = false + if (status == 'success') { + this._resetReload() + const index = this.contents.findIndex(item => item.chapter == content.chapter) + if (index > -1) { + this.contents[index] = content + } else { + this.contents.push(content) + } + this.resetPage({ + start: this.loadstart || 0, + currentChapter: this.loadchapter + }) + } else { + this.loadstatus = status + } + }) + } + }, + _resetReload () { + this.loadstatus = ''; + this.loadchapter = -1; + this.loadstart = -1; + }, //跳转 change (data) { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } + this.stopAutoplay() + this.clearRefreshTimer() + this._resetReload() if ( data.contents && data.contents.length > 0 ) { data.contents.forEach(item => { let index = this.contents.findIndex(content => content.chapter == item.chapter) @@ -552,10 +607,71 @@ currentChapter: parseInt(data.currentChapter || 1) }) } else { - uni.showToast({ - title: '未找到该章节内容', - icon: 'none' - }) + if ( this.noChapter ) { + uni.showToast({ + title: '未找到该章节', + icon: 'none' + }) + } else { + this.initLoading = true; + this.$emit('loadmore', parseInt(data.currentChapter), (status, content) => { + this.initLoading = false + if (status == 'success') { + const index = this.contents.findIndex(item => item.chapter == content.chapter) + if (index > -1) { + this.contents[index] = content + } else { + this.contents.push(content) + } + this.resetPage({ + start: parseInt(data.start || 0), + currentChapter: parseInt(data.currentChapter || 1) + }) + } else { + this.loadstatus = status; + this.loadstart = parseInt(data.start || 0) + this.loadchapter = parseInt(data.currentChapter || 1); + } + }) + } + } + }, + //翻往上一页 + pagePrev () { + this.stopAutoplay() + if ( this.options.pageType != 'scroll' ) { + this.pagePrevFlip() + } else { + this.scrollPrev() + } + }, + //翻往下一页 + pageNext () { + this.stopAutoplay() + if ( this.options.pageType != 'scroll' ) { + this.pageNextFlip() + } else { + this.scrollNext() + } + }, + startAutoplay () { + if ( this.autoplay && this.pages.length > 0 && this.pages.findIndex(page => page.dataId == this.currentDataId) < this.pages.length - 1 ) { + this.stopAutoplay() + this.autoplayTimer = setTimeout(() => { + this.pageNext() + }, this.autoplayTime) + } + }, + stopAutoplay () { + if ( this.autoplayTimer ) { + clearTimeout(this.autoplayTimer) + this.autoplayTimer = null + } + }, + clearRefreshTimer () { + if ( this.refreshTimer ) { + clearTimeout(this.refreshTimer) + this.refreshTimer = null } }, initFont () { @@ -576,84 +692,58 @@ }) // #endif }) - }, + } }, watch: { pageType (newVal, oldVal) { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - if ( newVal != 'scroll' ) { - this.getViewRect().then(res => { - this.refresh() - }) - } else { - this.refresh() - } - }, 100) + this.refresh() }) }, fontSize () { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - this.refresh() - }, 100) + this.refresh() }) }, lineHeight () { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - this.refresh() - }, 100) + this.refresh() }) }, slide () { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - this.refresh() - }, 100) + this.refresh() }) }, topGap () { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - this.refresh() - }, 100) + this.refresh() }) }, bottomGap () { this.$nextTick(function () { - if ( this.refreshTimer ) { - clearTimeout(this.refreshTimer) - this.refreshTimer = null - } - this.refreshTimer = setTimeout(() => { - this.refresh() - }, 100) + this.refresh() + }) + }, + firstTipUnable () { + this.$nextTick(function () { + this.refresh() + }) + }, + lastTipUnable () { + this.$nextTick(function () { + this.refresh() + }) + }, + fontFamily () { + this.$nextTick(async function () { + await this.getComputedTextSize() + this.refresh() }) }, fontFace () { this.initFont() - }, + } } } @@ -680,11 +770,9 @@ } - - - diff --git a/uni_modules/yingbing-flip/js_sdk/util.js b/uni_modules/yingbing-flip/js_sdk/util.js new file mode 100644 index 0000000..d3c3db9 --- /dev/null +++ b/uni_modules/yingbing-flip/js_sdk/util.js @@ -0,0 +1,446 @@ + +export default { + /** + * 补零 + * @param {Number} val 数字 + **/ + zeroize (val) { + return zeroize(val); + }, + /** + * 时间格式化 + * @param {String} time 时间戳or时间 + **/ + dateFormat (time, formats = 'yyyy-mm-dd hh:mm:ss') { + let arr = formats.split(' ') + let dateFormats = '' + let timeFormats = '' + arr.forEach(item => { + if ( item.indexOf('yy') > -1 ) { + dateFormats = item + } else { + timeFormats = item + } + }) + const d = new Date(time); + let result = '' + if ( dateFormats.indexOf('yyyy') > -1 ) { + result += d.getFullYear() + '-' + } + if ( dateFormats.indexOf('mm') > -1 ) { + result += zeroize(d.getMonth() + 1) + '-' + } + if ( dateFormats.indexOf('dd') > -1 ) { + result += zeroize(d.getDate()) + ' ' + } + if ( timeFormats.indexOf('hh') > -1 ) { + result += zeroize(d.getHours()) + ':' + } + if ( timeFormats.indexOf('mm') > -1 ) { + result += zeroize(d.getMinutes()) + ':' + } + if ( timeFormats.indexOf('ss') > -1 ) { + result += zeroize(d.getSeconds()) + ':' + } + return result.substring(0, result.length - 1) + }, + /** + * 秒数转化为分秒 + * @param {String} value 秒数 + **/ + minutesFormat (value) { + let minutes = Math.floor(value / 60 % 60) >= 10 ? Math.floor(value / 60 % 60) : '0' + Math.floor(value / 60 % 60); + let seconds = Math.floor(value % 60) >= 10 ? Math.floor(value % 60) : '0' + Math.floor(value % 60); + return minutes + ':' + seconds; + }, + /** + * 时间转化为秒数 + * @param {String} time 时间(HH:mm:ss) + **/ + time2seconds (time){ + const seconds = parseInt(time.split(':')[0]) * 60 + parseInt(time.split(':')[1].split('.')[0]) + parseInt(time.split(':')[1].split('.')[1]) / 1000; + return seconds; + }, + /** + * 移除url地址域名 + * @param {String} str http地址 + **/ + removeUrl (url) { + let str = url.replace(/^http:\/\/[^/]+/, ''); + return str.substr(1); + }, + /** + * 获取文件后缀 + * @param {String} name 带后缀的文件名称 + **/ + suffix (name) { + //获取图片后缀 + let fileName = name.lastIndexOf("."); + let fileNameLength = name.length; + let fileFormat = name.substring(fileName + 1, fileNameLength); + return fileFormat; + }, + + /** + * 清除文件后缀 + * @param {String} name 带后缀的文件名称 + */ + removeSuffix (name) { + //获取图片后缀 + let fileName = name.lastIndexOf("."); + if ( fileName > -1 ) { + let fileNameFormat = name.substring(0, fileName); + return fileNameFormat; + } else { + return name + } + }, + + /** + * 数组查找符合条件元素并返回下标 + * @param {Array} arr 传入数组 + * @param {String} value 条件元素 + * @param {String} query 对比key值 + */ + indexOf (arr, query, value) { + let len = arr.length; + for ( let i = 0; i < len; i++ ) { + if ( arr[i][query] == value ) { + return parseInt(i); + } + } + return -1; + }, + + /** + * 正则匹配 + * @param {String} type 匹配类型 + * @param {String} value 匹配值 + */ + reg (type, value) { + const regs = { + //身份证证则 + idcard: new RegExp(/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/), + //手机正则 + mobile: new RegExp(/^1[3456789]\d{9}$/), + //固定电话正则 + phone: new RegExp(/^(\(\d{3,4}\)|\d{3,4}-|\s)?\d{7,14}$/), + //金额验证 + price: new RegExp(/^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0.\d{1,2}$/), + //邮箱验证 + email: new RegExp(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/), + //银行卡 + bankcard: new RegExp(/^([1-9]{1})(\d{15}|\d{18})$/) + } + return regs[type].test(value); + }, + /** + * 计算2个时间差的分钟数或者秒钟数或时钟数 + * @param {datetime} time1 开始时间 + * @param {datetime} time2 结束时间 + */ + timeMinuse (time1, time2, type = 'minutes') { + //判断开始时间是否大于结束日期 + let date1 = new Date(time1); + let date2 = new Date(time2); + if ( date1 > date2 ) { + console.log("开始时间不能大于结束时间!"); + return false; + } + let seconds = date2.getTime() / 1000 - date1.getTime() / 1000; + return type == 'minutes' ? (seconds / 60) : type == 'hours' ? (seconds / 60 / 60) : seconds; + }, + /** + * 判断值类型返回字符 + * @param {datetime} value 需要判断类型的值 + */ + typeof (value) { + let type = Object.prototype.toString.call(value); + return type.slice(8, type.length - 1) + }, + /** + * 生成随机字符串 + * @param {Number} len 长度 + */ + randomString (len) { + len = len || 32; + var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/ + var maxPos = $chars.length; + var pwd = ''; + for (let i = 0; i < len; i++) { +   pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); + } + return pwd; + }, + + /** + * 生成随机ID + */ + randomID () { + let mydate = new Date(); + return mydate.getMinutes() + mydate.getSeconds() + mydate.getMilliseconds() + Math.round(Math.random() * 10000); + }, + + /** + * 生成随机不重复整数 + * @param {Number} len 长度 + */ + randomSoleNumber (len) { + let min = 0; + let max = len - 1; + let arr = []; + while ( arr.length < len ) { + let value = Math.floor(Math.random() * (max - min + 1)) + min; + if ( arr.indexOf(value) == -1 ) { + arr.push( value ) + } + } + return arr; + }, + + /** + * 16进制颜色转化为rgb + * @param {String} hex 16进制颜色 + */ + hex2rgb (hex) { + hex = hex.length == 7 ? hex : '#' + hex.slice(1, 4) + hex.slice(1, 4) + let str="rgb(" + const r = parseInt(hex.slice(1,3),16).toString(); //ff slice不包括end + const g = parseInt(hex.slice(3,5),16).toString(); //00 + const b = parseInt(hex.slice(5,7),16).toString(); //ff + str += r+","+g+","+b+")"; + return str + }, + + /** + * 16进制颜色转化为rgba + * @param {String} hex 16进制颜色 + */ + hex2rgba (hex, opacity) { + hex = hex.length == 7 ? hex : '#' + hex.slice(1, 4) + hex.slice(1, 4) + let str="rgba(" + const r = parseInt(hex.slice(1,3),16).toString(); //ff slice不包括end + const g = parseInt(hex.slice(3,5),16).toString(); //00 + const b = parseInt(hex.slice(5,7),16).toString(); //ff + str += r+","+g+","+b+","+opacity+")"; + return str + }, + + /** + * byte转化为文件大小 + * @param {Number} byte 位 + */ + byte2Size (byte) { + let sizeString = '' + if(byte == 0){ + sizeString = "0B"; + }else if(byte < 1024){ + sizeString = byte + "B"; + }else if(byte < 1048576){ + sizeString = (byte/1024).toFixed(2) + "KB"; + }else if (byte < 1073741824){ + sizeString = (byte/1048576).toFixed(2) + "MB"; + }else{ + sizeString = (byte/1073741824).toFixed(2) + "GB"; + } + return sizeString; + }, + + // 深度克隆 + deepClone (obj) { + if(typeof obj !== "object" && typeof obj !== 'function') { + //原始类型直接返回 + return obj; + } + var o = isArray(obj) ? [] : {}; + for(let i in obj) { + if(obj.hasOwnProperty(i)){ + o[i] = typeof obj[i] === "object" ? this.deepClone(obj[i]) : obj[i]; + } + } + return o; + }, + + /** + * 将数字转为带中文单位的字符串 + * @param {Number} num 数字 + */ + numtounit (num) { + let units = [{ + label: '万', + value: 10000, + min: 1000 + },{ + label: '亿', + value: 100000000, + min: 100000000 + },{ + label: '兆', + value: 10000000000000000, + min: 100000000000000000 + }] + let value = num + units.forEach(unit => { + if ( num >= unit.min ) { + value = (num / unit.value).toFixed(2) + unit.label + } + }) + return value + }, + /** + * 判断像素单位,没有则加上rpx + * @param {String} value 像素 + */ + pixelunit (value) { + if ( value.toString().indexOf('px') > -1 || value.toString().indexOf('em') > -1 || value.toString().indexOf('auto') > -1 || value.toString().indexOf('%') > -1 ) { + return value + } else { + return value + 'rpx' + } + }, + /** + * 判断像素单位,全部转为px + * @param {String} value 像素 + */ + unitpixel (value) { + if ( value.toString().indexOf('rpx') > -1 ) { + return uni.upx2px(value.replace('rpx', '')) + } else if ( value.toString().indexOf('px') > -1 ) { + return parseFloat(value.replace('px', '')) + } else if ( value.toString().indexOf('em') > -1 || value.toString().indexOf('auto') > -1 || value.toString().indexOf('%') > -1 ) { + return value + } else { + return parseFloat(uni.upx2px(value)) + } + }, + /** + * 判断像素单位,转化为rpx + * @param {String} value 值 + * @param {String} unit 返回结果是否带上单位 + */ + anytorpx (value, unit = true) { + if ( value.toString().indexOf('rpx') > -1 ) { + return unit ? value : parseFloat(value.replace('rpx', '')) + } else if ( value.toString().indexOf('px') > -1 ) { + return parseFloat(value.replace('px', '') * (750 / uni.getSystemInfoSync().windowWidth)) + (unit ? 'rpx' : 0) + } else if ( value.toString().indexOf('auto') > -1 ) { + return 'auto' + } else if ( value.toString().indexOf('%') > -1 ) { + return parseFloat((value.replace('%', '') / 100) * 750) + (unit ? 'rpx' : 0) + } else if (value.toString().indexOf('em') > -1 || value.toString().indexOf('rem') > -1 ) { + return parseFloat(value.replace('em', '').replace('rem', '') * 32) + (unit ? 'rpx' : 0) + } else if ( /^\d+$/.test(value) ) { + return parseFloat(value) + (unit ? 'rpx' : 0) + } + }, + /** + * 判断像素单位,转化为px + * @param {String} value 值 + * @param {String} unit 返回结果是否带上单位 + */ + anytopx (value, unit = false) { + if ( value.toString().indexOf('rpx') > -1 ) { + return uni.upx2px(value.replace('rpx', '')) + (unit ? 'px' : 0) + } else if ( value.toString().indexOf('px') > -1 ) { + return parseFloat(value.replace('px', '')) + (unit ? 'px' : 0) + } else if ( value.toString().indexOf('auto') > -1 ) { + return 'auto' + } else if ( value.toString().indexOf('%') > -1 ) { + return parseFloat((value.replace('%', '') / 100) * uni.getSystemInfoSync().windowWidth) + (unit ? 'px' : 0) + } else if (value.toString().indexOf('em') > -1 || value.toString().indexOf('rem') > -1 ) { + return parseFloat(value.replace('em', '').replace('rem', '') * uni.getSystemInfoSync().windowWidth) + (unit ? 'px' : 0) + } else if ( /^\d+$/.test(value) ) { + return parseFloat(value) + (unit ? 'px' : 0) + } + }, + getRefs (components, name, current) { + // #ifndef MP + return current >= 0 ? components.$refs[name][current] : components.$refs[name] + // #endif + // #ifdef MP + return {} + // #endif + }, + //获取节点 + getEl (el) { + if (typeof el === 'string' || typeof el === 'number') return el; + if (WXEnvironment) { + return el.ref; + } else { + return el instanceof HTMLElement ? el : el.$el; + } + }, + /** + * 获取指定父节点 + * @param {String} components 当前实例 + * @param {String} name 父节点名称 + */ + getParent(name, components) { + let parent = components.$parent + if (parent) { + let parentName = parent.$options.name + while (parentName !== name) { + parent = parent.$parent + if (parent) { + parentName = parent.$options.name + } else { + return null + } + } + return parent + } + return null + }, + /** + * 获取指定子节点 + * @param {String} components 当前实例 + * @param {String} name 父节点名称 + */ + getChildrens(names, components) { + let arr = [] + let childs = names.split(',') + const dowhile = (children) => { + if ( this.typeof(children) == 'Array' ) { + children.forEach(child => { + if ( childs.indexOf(child.$options.name) > -1 ) { + arr.push(child) + } + if ( child.$children && child.$children.length > 0 ) { + dowhile(child.$children) + } + }) + } + } + dowhile(components.$children) + return arr; + }, + /** + * 获取指定子节点 + * @param {String} selector 节点class或者id + * @param {String} el 节点 + * @param {String} components 当前实例 + */ + getRect (selector, el, components) { + return new Promise(resolve => { + // #ifdef APP-NVUE + uni.requireNativePlugin('dom').getComponentRect(el, res => { + resolve(res.size) + }) + // #endif + // #ifndef APP-NVUE + uni.createSelectorQuery().in(components).select(selector).boundingClientRect(data => { + resolve(data) + }).exec(); + // #endif + }) + } +} + +// 判断arr是否为一个数组,返回一个bool值 +function isArray (arr) { + return Object.prototype.toString.call(arr) === '[object Array]'; +} + +function zeroize (val) { + return val >= 10 ? val : '0' + val; +} diff --git a/uni_modules/yingbing-flip/package.json b/uni_modules/yingbing-flip/package.json new file mode 100644 index 0000000..a3b1c76 --- /dev/null +++ b/uni_modules/yingbing-flip/package.json @@ -0,0 +1,81 @@ +{ + "id": "yingbing-flip", + "displayName": "好用翻页组件", + "version": "1.0.4", + "description": "高性能翻页组件", + "keywords": [ + "翻页" +], + "repository": "https://gitee.com/yingbing-developer/yingbing-flip.git", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "Vue": { + "vue2": "u", + "vue3": "u" + }, + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u", + "钉钉": "u", + "快手": "u", + "飞书": "u", + "京东": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yingbing-flip/readme.md b/uni_modules/yingbing-flip/readme.md new file mode 100644 index 0000000..b04edfe --- /dev/null +++ b/uni_modules/yingbing-flip/readme.md @@ -0,0 +1,344 @@ +#使用须知 + +* 1、这是一个翻页组件,适用于小说翻页或答题功能 +* 2、这个插件支持APP-NVUE、APP-VUE、H5、微信小程序 +* 3、该组件滑动项同时只能存在当前项、前面项、后面项3个,其余项会被销毁 +* 4、如果想要构建阅读器需要配合[好用阅读分页插件](https://ext.dcloud.net.cn/plugin?id=6026)使用 +* 5、有什么不懂,可以加群 1087735942 聊 + +#props属性 +| 属性名 | 类型 | 默认值 | 可选值 | 说明 | +| :----- | :----: | :----: | :----: | :---- | +| data | Array | ---- | ---- | 列表数据 | +| current | Number | 0 | ---- | 初始化位置 | +| vertical | Boolean | false | true/false | 垂直滑动 | +| duration | Number | 100 | ---- | 滑动动画时间 | +| bgColor | String | ---- | ---- | 背景色 | +| pulldownable | Boolean | false | true/false | 开启下拉刷新 | +| pullupable | Boolean | false | true/false | 开启上拉加载 | +| pulldownHeight | Number | 80 | ---- | 下拉刷新控件高度(px) | +| pullupHeight | Number | 80 | ---- | 上拉加载控件高度(px) | +| sliderFault | Number | 20 | ---- | 滑动容错距离(px) | +| type | String | real | real(仿真)/cover(覆盖)/none(无动画) | 翻页方式 | +| unableClickPage | Boolean | false | true/false | 关闭点击左右2侧翻页功能(type为none时忽略此属性) | + +#event事件 +| 事件名 | 参数 | 说明 | +| :----- | :----: | :---- | +| change | current: 当前滑动位置, detail: 当前滑动位置列表数据 | 位置改变事件 | +| pulldown | callback: 回调 | 下拉刷新事件 | +| pullup | callback: 回调 | 上拉加载事件 | + +#内置方法 +| 方法名 | 参数 | 说明 | +| :--- | :------ | :---- | +| refresh | ---- | 刷新滑动位置(替换数据时使用) | +| flipToNext | ---- | 翻到到下个位置 | +| flipToPrev | ---- | 翻到上个位置 | + +#slot插槽 +| 名称 | 说明 | +| :----- | :---- | :---- | +| pulldownDefault | 下拉加载默认提示 | +| pulldownReady | 下拉加载准备提示 | +| pulldownLoading | 下拉加载等待提示 | +| pulldownSuccess | 下拉加载成功提示 | +| pulldownFail | 下拉加载失败提示 | +| pullupDefault | 上拉加载默认提示 | +| pullupReady | 上拉加载准备提示 | +| pullupLoading | 上拉加载等待提示 | +| pullupSuccess | 上拉加载成功提示 | +| pullupFail | 上拉加载失败提示 | + + +#快速开始 +```html + + +