Commit 8190e475 authored by jyx's avatar jyx

添加翻页功能

parent 2c05a1c9
......@@ -7,9 +7,9 @@
<setting-pop :show='showSetting' @close='closePop'></setting-pop>
<catalogue-pop :detail='bookData' :show='showCatalogue' @close='closeCataPop'
@tabVip='tapVipPop'></catalogue-pop>
<vip-pop v-if="bookData.isUnlock==0 && !isVip()" :show='showVip' @close='closeVipPop'></vip-pop>
<!-- <vip-pop v-if="bookData.isUnlock==0 && !isVip()" :show='showVip' @close='closeVipPop'></vip-pop>
<bean-pop v-if="bookData.isUnlock==0 && userInfo.bookLegumes<bookData.bookLegumes" :show='showBean'
@close='closeBeanPop'></bean-pop>
@close='closeBeanPop'></bean-pop> -->
<recommend-pop :show='showRecommend' @close='closeRecommendPop' :bookId="bookId"></recommend-pop>
</template>
<!-- <c-login :isShareLink="true"></c-login> -->
......
......@@ -98,7 +98,8 @@
// 文章数据刷新
refreshChapterinfoData(chapterId, callback) {
this.catalogue = chapterId
getChapterinfoData(this.detail.id, chapterId, (success, data) => {
let id = this.detail.articleChapterList[chapterId].id
getChapterinfoData(this.detail.id, id, (success, data) => {
if (success) {
this.changeChapterinfo(chapterId, data.content)
}
......
......@@ -20,7 +20,7 @@ import CatalogueList from "../models/CatalogueList";
*/
function getBookDetailData(bookId, callback) {
apiPOST({
url: `/readSystem/v1/article/info`,
url: `/book/info`,
data: {
id: bookId
},
......@@ -35,7 +35,7 @@ function getBookDetailData(bookId, callback) {
*/
function getChapterinfoData(bookId, chapterId, callback) {
apiPOST({
url: `/readSystem/v1/article/chapterinfo`,
url: `/book/chapterinfo`,
data: {
articleId: bookId,
chapterId: chapterId,
......@@ -50,7 +50,7 @@ function getChapterinfoData(bookId, chapterId, callback) {
*/
function getBookRecommendData(bookId, callback) {
apiPOST({
url: `/readSystem/v1/article/recommend`,
url: `/book/recommend`,
data: {
id: bookId
},
......@@ -63,7 +63,7 @@ function getBookRecommendData(bookId, callback) {
*/
function addReadRecord(bookId, callback) {
apiPOST({
url: `/readSystem/system/readRecord/addReadRecord`,
url: `/book/addReadRecord`,
data: {
articleId: bookId
},
......
## 1.6.0(2023-12-22)
* measureSize增加藏文字符测量
* 增加charSize属性单独定义字符尺寸
* split属性增加多字符兼容
## 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属性添加自定义字体
## 1.4.2(2023-05-25)
* 修复IOS电量显示
## 1.4.1(2023-05-24)
* 修复单章节内容太短可能会引起得卡死和报错
## 1.4.0(2023-04-04)
* 优化翻页模式,减少闪烁问题
## 1.3.9(2023-04-03)
* 优化APP端电量获取,修复获取电量可能会造成闪退的问题
* 修复APP-NVUE翻页模式加载下一章节会闪烁的问题
## 1.3.8(2023-04-01)
* 修复APP-NVUE 向前翻页会闪烁的问题
* 删除一些不必要的代码文件
## 1.3.7(2023-04-01)
* APP-NVUE使用webview替代rich-text实现自定义页面
* APP-NVUE自定义页面支持添加自定义点击事件
* 稍微优化了一下翻页
## 1.3.6(2023-03-15)
* 修复在低端机上,分页会卡住的问题
## 1.3.5(2023-03-14)
* 优化整书模式的分页
## 1.3.4(2023-03-13)
* 修复APP-NVUE一些问题
## 1.3.3(2023-03-13)
* 优化滚动模式定位问题
## 1.3.2(2023-03-01)
* 修复整书模式 init初始化 无效果的 bug
## 1.3.1(2023-01-04)
* 修复直接点击上一页,文字不显示的bug
## 1.3.0(2022-12-20)
* 新增APP-NVUE和微信小程序支持
* 新增自定义插槽功能
* 整书模式已整合进入章节模式,表现效果和章节模式相同
* 新增页面顶部和底部的电池电量、章节、事件,页数显示
## 1.2.9(2022-09-06)
* 修复滑动过快造成翻页动画异常的bug
* 修复调用refresh方法报错的bug
* 修复翻页动画有时候方向判断错误的bug
* 滚动模式不再使用better-scroll插件,改用自己写的滚动组件
* 添加pageNext, pagePrev翻页方法
## 1.2.8(2022-06-08)
* 更改整书模式的翻页方法(上次更新忘记改了)
## 1.2.7(2022-06-04)
* 添加自定义页面功能(可用于付费章节、广告展示等)
* 更改触摸翻页方式,现在页面上任何地方都能触摸翻页
* 减小了翻页需要的距离
* 减少了翻页节流时间
## 1.2.6(2022-02-14)
* 修复向前点击翻页出现2种动画的bug
## 1.2.5(2021-10-19)
* 优化整书模式一些问题
## 1.2.4(2021-10-18)
* 修复滚动模式定位问题
## 1.2.3(2021-10-17)
* 添加点击区域配置,具体见下面得介绍
## 1.2.2(2021-10-17)
* 优化滚动模式
## 1.2.1(2021-10-15)
* 优化滚动模式逻辑
## 1.2.0(2021-10-15)
* 修复滚动模式下得问题
## 1.1.9(2021-10-15)
* 修复一些显示问题
* 优化了一下滚动模式滚动效果
## 1.1.8(2021-10-14)
* content对象中可以带上章节名称,方便取值
* 增加初始化loading效果
## 1.1.7(2021-10-14)
* 增加整书模式返回得页面信息
## 1.1.6(2021-10-14)
* 更改整书模式返回章节集合得参数
## 1.1.5(2021-10-14)
* 优化翻页得性能,同时最多显示3张页面
## 1.1.4(2021-10-13)
修复一些问题
## 1.1.3(2021-10-13)
* 修复一些问题
## 1.1.2(2021-10-13)
* 修复一些问题
## 1.1.1(2021-10-13)
* 修复了一些问题
## 1.1.0(2021-10-12)
* 此次更新为重构插件
* 首先感谢一下2位插件使用者提供的反馈
* 主要更新如下:
- 1、为请求事件增加了过渡效果,滚动模式下增加上拉和下拉操作
- 2、解决了一些逻辑问题,现在preload和loadmore事件触发更合理
- 3、其它都是些小更新,比如章节模式下currentChange事件增加了返回的页面信息
- 4、更改了参数结构,请注意阅读使用须知
## 1.0.5(2021-09-22)
* 修复上次更新引起无法翻到上一页的问题
## 1.0.4(2021-09-22)
* 修复横向翻页部分页面不绘制的bug
## 1.0.3(2021-09-05)
* 修复整书模式下阅读小说到最后面,下一页会从小说最前面再次排版的bug
## 1.0.2(2021-09-04)
* 修复预加载章节内容无效的问题
* 添加初始化触发currentChange事件
## 1.0.1(2021-08-29)
* 减少滚动模式下触底加载更多时的滚动距离
## 1.0.0(2021-08-28)
* 发布1.0.0版本
<template>
<view class="yingbing-battery">
<view class="yingbing-battery-wrapper" :style="{
'border-color': color
}">
<view class="yingbing-battery-content">
<view :style="{
flex: 1,
'background-color': color,
width: value + 'rpx'
}"></view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
color: {
type: String,
default: '#333'
}
},
data () {
return {
value: 54
}
},
// #ifdef APP-PLUS
beforeDestroy() {
if ( this.recevier ) {
plus.android.runtimeMainActivity().unregisterReceiver(this.recevier)
}
},
// #endif
created () {
this.getBattery()
},
methods: {
getBattery () {
// #ifdef H5
//window.navigator.getBattery只能在安全环境下(比如:https file:///url)使用,判断一下避免报错
window.navigator.getBattery && window.navigator.getBattery().then((res) => {
// 电池电量在0到1之间,因此我们将其乘以100得出百分比
this.value = res.level * 54
});
// #endif
// #ifdef MP-WEIXIN
wx.getBatteryInfo({
success: (res) => {
this.value = (res.level / 100) * 54
}
})
// #endif
// #ifdef APP-PLUS
uni.getSystemInfo({
success: (res) => {
if ( res.osName == 'android' ) {
const main = plus.android.runtimeMainActivity()
const Intent = plus.android.importClass('android.content.Intent');
this.recevier = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', { 
onReceive: (context, intent) => { 
       let action = intent.getAction(); 
       if (action == Intent.ACTION_BATTERY_CHANGED) { 
            let level = intent.getIntExtra("level", 0); //电量 B5教程网 
this.value = (level / 100) * 54
main.unregisterReceiver(this.recevier)//销毁注册广播
//let voltage = intent.getIntExtra("voltage", 0); //电池电压 
//let temperature = intent.getIntExtra("temperature", 0); //电池温度 
           //如需获取别的,在这里继续写,此代码只提供获取电量 
       } 
    } 
}); 
const filter = plus.android.newObject('android.content.IntentFilter', Intent.ACTION_BATTERY_CHANGED); 
main.registerReceiver(this.recevier, filter);
} else if ( res.osName == 'ios' ) {
const UIDevice = plus.ios.import("UIDevice");
const dev = UIDevice.currentDevice(); 
if (!dev.isBatteryMonitoringEnabled()) { 
    dev.setBatteryMonitoringEnabled(true); 
} 
let level = dev.batteryLevel();
this.value = level * 54
}
}
})
// #endif
}
}
}
</script>
<style scoped>
.yingbing-battery-wrapper {
width: 60rpx;
height: 24rpx;
border-width: 1px;
border-style: solid;
padding: 2rpx;
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
/* #endif */
}
.yingbing-battery-content {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
/* #endif */
}
</style>
\ No newline at end of file
.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
.yingbing-read-page-flip {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.flip-item-wrapper {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
box-sizing: border-box;
/* #endif */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.flip-item-header {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
box-sizing: border-box;
/* #endif */
justify-content: center;
height: 50rpx;
overflow: hidden;
}
.flip-item-header-text {
font-size: 24rpx;
opacity: .4;
font-weight: bold;
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
/* #ifndef APP-NVUE */
display: -webkit-box !important;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
-webkit-box-orient:vertical;
-webkit-line-clamp: 1;
/* #endif */
}
.flip-item-footer {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
/* #endif */
align-items: center;
flex-direction: row;
justify-content: space-between;
height: 50rpx;
overflow: hidden;
}
.flip-item-footer-text {
font-size: 24rpx;
opacity: .4;
font-weight: bold;
}
.flip-item-content {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
/* #endif */
flex: 1;
}
.flip-item-text {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
/* #endif */
},
.flip-text {
/* #ifndef APP-NVUE */
box-sizing: border-box;
white-space: pre-wrap;
/* #endif */
}
.flip-loading {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.flip-loading-text {
font-size: 20px;
}
/* #ifndef APP-NVUE */
view, image, input, scroll-view, swiper, swiper-item, text, textarea, video {
position: static;
}
/* #endif */
\ No newline at end of file
import Util from '../../../js_sdk/util.js'
export default {
computed: {
current () {
return this.pages.findIndex(item => item.dataId == this.currentDataId)
},
prevDataId () {
return this.pages[this.current - 1] && this.pages[this.current - 1].dataId
},
nextDataId () {
return this.pages[this.current + 1] && this.pages[this.current + 1].dataId
}
},
data() {
return {
currentDataId: -1,
isShow: false,
viewWidth: 0,
moreLoading: false
}
},
methods: {
//翻往上一页
pagePrevFlip () {
this.$refs.flip.flipToPrev()
},
//翻往下一页
pageNextFlip () {
this.$refs.flip.flipToNext()
},
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);
},
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) {
this.contents[index] = content;
} else {
this.contents.push(content);
}
this.computedPage({
content: content,
type: value > 0 ? 'next' : 'prev'
});
this.preload(chapter)
} else {
let loadIndex = this.pages.findIndex(page => page.type == 'loading' && page.direction == (value > 0 ? 'next' : 'prev'))
this.$set(this.pages[loadIndex], 'type', status)
}
})
},
handleFlipChangeRender (e) {
this.handleFlipChange(e.detail.dataId)
},
handleFlipChange (dataId) {
const value = dataId < this.currentDataId ? -1 : 1
this.currentDataId = dataId
const index = this.pages.findIndex(page => page.dataId == dataId);
let pageInfo = this.pages[index]
const nowChapters = this.pages.filter(item => item.chapter == pageInfo.chapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot'))
let contentIndex = this.contents.findIndex(content => content.chapter == pageInfo.chapter)
pageInfo.totalPage = nowChapters.length
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._emitPageInfo(pageInfo, this.pages)
const nextType = this.pages[index + value] && this.pages[index + value].type
if ( this.pages[index].type == 'loading' || nextType == 'loading') {
if (this.moreLoading) return
this.moreLoading = true;
const loadChapter = this.pages[index].chapter + value;
contentIndex = this.contents.findIndex(content => content.chapter == loadChapter)
if (contentIndex > -1) {
this.computedPage({
content: this.contents[contentIndex],
type: value > 0 ? 'next' : 'prev'
});
this.preload(loadChapter)
this.moreLoading = false;
} else {
this.loadmoreFlip(loadChapter, value)
}
} else {
this.startAutoplay()
}
}
}
}
\ No newline at end of file
<template>
<view class="yb-list yb-flex">
<!-- #ifdef APP-VUE || H5 || MP-WEIXIN || MP-QQ -->
<view class="yb-refresh yb-flex yb-flex-1"
:prop="pulldownProp" :change:prop="pulldownwxs.propWatcher"
@touchstart="pulldownwxs.touchstart"
@touchmove="pulldownwxs.touchmove"
@touchend="pulldownwxs.touchend">
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view class="yb-refresh yb-flex yb-flex-1" ref="ybRefresh">
<!-- #endif -->
<!-- #ifdef APP-VUE || H5 || MP-WEIXIN || MP-QQ -->
<view ref="ybListPulldown" class="yb-list-pulldown yb-flex">
<list-pulldown :status="pulldownStatus" :options="pulldownOptionsSync">
<template v-slot:pulldown-symbol>
<slot name="pulldown-symbol"></slot>
</template>
<template v-slot:pulldown-loading>
<slot name="pulldown-loading"></slot>
</template>
<template v-slot:pulldown-success>
<slot name="pulldown-success"></slot>
</template>
<template v-slot:pulldown-fail>
<slot name="pulldown-fail"></slot>
</template>
<template v-slot:pulldown-end>
<slot name="pulldown-end"></slot>
</template>
</list-pulldown>
</view>
<!-- #endif -->
<scroll-view
scroll-y
:render-whole="true"
@scroll="onScroll"
:scroll-top="scrollTop"
:scroll-with-animation="scrollWithAnimation"
ref="ybPulldownScroller"
class="yb-pulldown-scroller yb-pulldown-scroll-view"
@scrolltoupper="onScrolltoupper"
@scrolltolower="onScrolltolower">
<!-- #ifdef APP-NVUE -->
<template v-if="pulldownOptionsSync.show">
<refresh :display="display" @pullingdown="pullingdown($event.pullingDistance)" @refresh="refresh">
<view class="yb-flex" style="height: 30rpx;"></view>
<list-pulldown :status="pulldownStatus" :options="pulldownOptionsSync">
<template v-slot:pulldown-symbol>
<slot name="pulldown-symbol"></slot>
</template>
<template v-slot:pulldown-loading>
<slot name="pulldown-loading"></slot>
</template>
<template v-slot:pulldown-success>
<slot name="pulldown-success"></slot>
</template>
<template v-slot:pulldown-fail>
<slot name="pulldown-fail"></slot>
</template>
<template v-slot:pulldown-end>
<slot name="pulldown-end"></slot>
</template>
</list-pulldown>
<view class="yb-flex" style="height: 20rpx;"></view>
</refresh>
</template>
<!-- #endif -->
<slot></slot>
<template v-if="loadmoreOptionsSync.show">
<list-loadmore :status="loadmoreStatus" :options="loadmoreOptionsSync" @reload="reload">
<template v-slot:loadmore-symbol>
<slot name="loadmore-symbol"></slot>
</template>
<template v-slot:loadmore-loading>
<slot name="loadmore-loading"></slot>
</template>
<template v-slot:loadmore-fail>
<slot name="loadmore-fail"></slot>
</template>
<template v-slot:loadmore-end>
<slot name="loadmore-end"></slot>
</template>
</list-loadmore>
</template>
</scroll-view>
</view>
</view>
</template>
<script>
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
import ListPulldown from './modules/pulldown/pulldown.vue'
import ListLoadmore from './modules/loadmore/loadmore.vue'
import PulldownMixin from './modules/pulldown/pulldown.js'
import LoadmoreMixin from './modules/loadmore/loadmore.js'
export default {
mixins: [PulldownMixin, LoadmoreMixin],
options: {
addGlobalClass: true,
virtualHost: true, // 将自定义节点设置成虚拟的,更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
},
components: {
ListPulldown,
ListLoadmore
},
props: {
//下拉加载配置
pulldown: {
type: [Object,Boolean],
default () {
return new Object
}
},
//触底加载更多配置
loadmore: {
type: [Object,Boolean],
default () {
return new Object
}
}
},
data () {
return {
scrollTop: 0,
scrollWithAnimation: false
}
},
computed: {
Util () {
return Util
}
},
methods: {
onScrolltoupper () {
this.$emit('scrolltoupper')
},
scrollTo (offset, animated = false) {
this.scrollWithAnimation = animated
this.$nextTick(function() {
this.scrollTop = offset - 1
this.$nextTick(function () {
this.scrollTop = offset
})
})
},
onScroll (e) {
this.$emit('scroll', {
scrollTop: e.detail.scrollTop,
scrollHeight: e.detail.scrollHeight,
scrollWidth: e.detail.scrollWidth
})
}
}
}
</script>
<!-- #ifdef APP-VUE || H5 || MP-WEIXIN || MP-QQ -->
<script module="pulldownwxs" lang="wxs" src="./modules/pulldown/pulldown.wxs"></script>
<!-- #endif -->
<style scoped>
@import url(@/uni_modules/yingbing-ReadPage/css/common.css);
.yb-list {
position: relative;
flex: 1;
}
.yb-list .yb-refresh {
position: relative;
/* #ifndef APP-NVUE */
overflow: visible;
/* #endif */
}
.yb-list .yb-list-pulldown {
height: 400rpx;
margin-top: -400rpx;
justify-content: flex-end;
padding: 40rpx 0;
}
.yb-pulldown-scroller {
/* #ifndef APP-NVUE */
overflow: visible;
/* #endif */
}
.yb-list .yb-pulldown-scroll-view {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
</style>
<template>
<view class="yb-flex">
<view class="yb-loading yb-flex yb-align-center">
<view v-if="visible" class="circle yb-flex" ref="loading" :style="{
width: pixelSize + 'px',
height: pixelSize + 'px',
'border-radius': pixelSize + 'px'
}">
<view
class="line yb-flex"
:style="{
'border-top-width': (pixelSize / 4) + 'px',
'border-bottom-width': (pixelSize / 4) + 'px',
'border-top-color': item.top,
'border-bottom-color': item.bottom,
width: (pixelSize / 12) + 'px',
left: ((pixelSize / 2) - (pixelSize / 24)) + 'px',
}"
:class="'line_' + index"
v-for="(item, index) in rgbs" :key="index"></view>
</view>
<text class="loading-text" :style="{color: color}" v-if="text && visible">{{text}}</text>
</view>
</view>
</template>
<script>
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
// #ifdef APP-NVUE
const Binding = uni.requireNativePlugin('bindingx')
// #endif
export default {
props: {
visible: {
type: Boolean,
default: false
},
size: {
type: [Number, String],
default: 40
},
color: {
type: String,
default: '#333333'
},
text: {
type: String,
default: ''
}
},
computed: {
rgbs () {
let rgb = Util.hex2rgb(this.color).replace('rgb(', '').replace(')', '')
return [{
top: `rgba(${rgb}, 1)`,
bottom: `rgba(${rgb}, .4)`
},{
top: `rgba(${rgb}, .4)`,
bottom: `rgba(${rgb}, .5)`
},{
top: `rgba(${rgb}, .4)`,
bottom: `rgba(${rgb}, .6)`
},{
top: `rgba(${rgb}, .4)`,
bottom: `rgba(${rgb}, .7)`
},{
top: `rgba(${rgb}, .4)`,
bottom: `rgba(${rgb}, .8)`
},{
top: `rgba(${rgb}, .4)`,
bottom: `rgba(${rgb}, .9)`
}]
},
pixelSize () {
return Util.unitpixel(this.size)
}
},
data () {
return {
loading_binding: null
}
},
mounted() {
// #ifdef APP-NVUE
this.$nextTick(() => {
if ( this.visible ) {
this.start()
}
})
// #endif
},
beforeDestroy() {
// #ifdef APP-NVUE
if ( this.loading_binding ) {
Binding.unbind({
token: this.loading_binding.token,
eventType: 'timing'
})
this.loading_binding = null
}
// #endif
},
methods: {
start () {
let loading = Util.getEl(this.$refs.loading);
this.loading_binding = Binding.bind({
eventType: 'timing',
props: [{
element: loading,
property: 'transform.rotateZ',
expression: 'floor(t/100)*30'
}]
});
}
},
watch: {
visible (newVal) {
// #ifdef APP-NVUE
this.$nextTick(() => {
if ( newVal ) {
this.start()
} else {
if ( this.loading_binding ) {
Binding.unbind({
token: this.loading_binding.token,
eventType: 'timing'
})
this.loading_binding = null
}
}
})
// #endif
}
}
}
</script>
<style scoped>
@import url(@/uni_modules/yingbing-ReadPage/css/common.css);
/* #ifndef APP-NVUE */
@keyframes loading{
0% {
transform: rotateZ(30deg);
}
9.33333%{
transform: rotateZ(60deg);
}
18.66666%{
transform: rotateZ(90deg);
}
27.99999%{
transform: rotateZ(120deg);
}
37.33332%{
transform: rotateZ(150deg);
}
46.66665%{
transform: rotateZ(180deg);
}
55.99998%{
transform: rotateZ(210deg);
}
65.33331%{
transform: rotateZ(240deg);
}
74.66664%{
transform: rotateZ(270deg);
}
83.99997%{
transform: rotateZ(300deg);
}
93.33333%{
transform: rotateZ(330deg);
}
100%{
transform: rotateZ(360deg);
}
}
/* #endif */
.yb-loading .loading-text {
margin-top: 15rpx;
font-size: 28rpx;
}
.circle {
position: relative;
/* #ifndef APP-NVUE */
animation: loading 1200ms step-start infinite;
/* #endif */
}
.circle .line {
position: absolute;
border-top-style: solid;
border-bottom-style: solid;
top: 0;
bottom: 0;
}
.circle .line_0 {
}
.circle .line_1 {
transform: rotateZ(30deg);
}
.circle .line_2 {
transform: rotateZ(60deg);
}
.circle .line_3 {
transform: rotateZ(90deg);
}
.circle .line_4 {
transform: rotateZ(120deg);
}
.circle .line_5 {
transform: rotateZ(150deg);
}
</style>
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
export default {
data () {
return {
isLoadmore: false,//是否触底
loadmoreStatus: '',//触底状态
isPageFirst: false//判断页面滚动时是否首次加载
}
},
computed: {
loadmoreOptionsSync () {
return Object.assign({}, {
//是否展示加载更多
show: false,
//是否采用row布局
row: false,
//默认文本
defaultText: '上拉或点击加载',
//刷新中的提示文本
refreshingText: '正在加载',
//刷新成功的文本
successText: '加载成功,点击继续',
//刷新失败的提示文本
failText: '加载失败,点击重试',
//数据全部加载完毕的提示文本
endText: '数据加载完毕',
//文本颜色
color: '#333333',
//距底部的距离
bottom: 0
}, Util.typeof(this.loadmore) == 'Object' ? this.loadmore : Util.typeof(this.loadmore) == 'Boolean' ? { show: this.loadmore } : {})
}
},
mounted () {
//页面滚动通过判断上拉加载组件是否出现在屏幕内来触发触发触底事件,组件初始化时不触发触底事件,延迟一秒后才能触发
this.$nextTick(function () {
setTimeout(() => {
this.isPageFirst = true
}, 1000)
})
},
methods: {
onScrolltolower () {
if ( !this.isPageFirst && this.typeSync == 'page' ) {
return
}
if ( this.isLoadmore ) {
return
}
this.isLoadmore = true
this.loadmoreStatus = 'loading'
this.$emit('loadmore', (state) => {
this.loadmoreStatus = state
if ( state != 'fail' && state != 'end') {
this.isLoadmore = false
// #ifdef APP-NVUE
this.$refs.ybPulldownScroller.resetLoadmore()
// #endif
}
})
},
//重置加载更多状态
resetLoadmore () {
this.loadmoreStatus = ''
this.isLoadmore = false
// #ifdef APP-NVUE
this.$refs.ybPulldownScroller.resetLoadmore()
// #endif
},
//设置加载更多为完毕状态
setLoadmoreEnd () {
this.loadmoreStatus = 'end'
this.isLoadmore = true
},
//设置加载更多为成功状态
setLoadmoreSuccess () {
this.loadmoreStatus = 'success'
this.isLoadmore = false
},
//设置加载更多为失败状态
setLoadmoreFail () {
this.loadmoreStatus = 'fail'
this.isLoadmore = false
},
//重加载更多
reload () {
this.isLoadmore = false
this.onScrolltolower()
}
}
}
\ No newline at end of file
<template>
<view class="yb-loadmore yb-flex yb-align-center yb-justify-center"
:class="{
'yb-row': options.row
}"
@tap="onTap" v-if="options.show">
<view class="yb-flex" style="height: 20rpx;"></view>
<view class="yb-flex yb-align-center yb-justify-center" :style="{'margin-left': options.row ? '-70rpx' : 0}">
<view class="yb-flex indicator-icon yb-align-center yb-justify-center">
<template v-if="status == ''">
<slot name="loadmore-symbol">
<slot name="loadmore-symbol">
<list-icon
name="arrow-up"
:size="50"
:color="options.color"></list-icon>
</slot>
</slot>
</template>
<template v-if="status == 'loading'">
<slot name="loadmore-loading">
<list-loading :visible="status == 'loading'" :color="options.color"></list-loading>
</slot>
</template>
<template v-if="status == 'fail'">
<slot name="loadmore-fail">
<list-icon
name="fork-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
<template v-if="status == 'success'">
<slot name="loadmore-success">
<list-icon
name="hook-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
<template v-if="status == 'end'">
<slot name="loadmore-end">
<list-icon
name="hook-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
</view>
</view>
<view class="yb-flex indicator-text yb-align-center">
<text class="refresh-text" :style="{color: options.color}">{{refreshText}}</text>
</view>
<view class="yb-flex" style="height: 20rpx;"></view>
<view class="yb-flex" :style="{
height: Util.pixelunit(options.bottom)
}"></view>
</view>
</template>
<script>
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
import ListIcon from '../common/icon.vue'
import ListLoading from '../common/loading.vue'
export default {
components: {
ListIcon,
ListLoading
},
props: {
options: {
type: Object,
default () {
return new Object
}
},
status: {
type: String,
default: ''
}
},
computed: {
refreshText () {
return this.status == 'loading' ? this.options.refreshingText : this.status == 'success' ? this.options.successText : this.status == 'fail' ? this.options.failText : this.status == 'end' ? this.options.endText : this.options.defaultText
},
Util () {
return Util
}
},
methods: {
onTap () {
if ( this.status != 'end' && this.status != 'loading' ) {
this.$emit('reload')
}
}
}
}
</script>
<style scoped>
@import url(@/uni_modules/yingbing-ReadPage/css/common.css);
.yb-loadmore .indicator-icon {
width: 70rpx;
height: 70rpx;
}
.yb-loadmore .refresh-text {
text-align: center;
font-size: 24rpx;
}
.yb-loadmore .indicator-symbol {
transition: transform .1s;
}
.yb-loadmore .refresh-time {
font-size: 23rpx;
}
</style>
\ No newline at end of file
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
export default {
data () {
return {
pulldownStatus: '',//下拉状态
pulldownRestore: false,//下拉复位
display: 'show'
}
},
computed: {
pulldownOptionsSync () {
return Object.assign({}, {
show: false,
//是否采用row布局
row: false,
//是否显示刷新时间
enableRefreshTime: true,
//默认文本
defaultText: '下拉刷新',
//准备刷新
readyText: '释放刷新',
//刷新中的提示文本
refreshingText: '正在刷新',
//刷新成功的提示文本
successText: '刷新成功',
//刷新失败的提示文本
failText: '刷新失败',
//刷新结束的提示文本
endText: '刷新完毕',
//文本颜色
color: '#333333',
//刷新完成后的隐藏周期
duration: 300
}, Util.typeof(this.pulldown) == 'Object' ? this.pulldown : Util.typeof(this.pulldown) == 'Boolean' ? { show: this.pulldown } : {})
},
pulldownProp () {
return {
pulldownRestore: this.pulldownRestore,
enablePulldown: this.pulldownOptionsSync.show
}
}
},
methods: {
refresh () {
if ( !this.pulldownOptionsSync.show ) {
return
}
if ( this.pulldownStatus != 'end' ) {
this.pulldownStatus = 'loading'
this.$emit('pulldown', (state) => {
this.pulldownStatus = state
this.pulldownTimer = setTimeout(() => {
this.pulldownRestore = true
clearTimeout(this.pulldownTimer)
this.pulldownTimer = null
// #ifdef APP-NVUE
this.display = 'hide';
this.pulldownTimer = setTimeout(() => {
this.display = 'show'
clearTimeout(this.pulldownTimer)
this.pulldownTimer = null
}, this.pulldownOptionsSync.duration)
// #endif
}, this.pulldownOptionsSync.duration)
})
} else {
this.pulldownRestore = true
// #ifdef APP-NVUE
this.display = 'hide';
this.pulldownTimer = setTimeout(() => {
this.display = 'show'
clearTimeout(this.pulldownTimer)
this.pulldownTimer = null
}, this.pulldownOptionsSync.duration)
// #endif
}
},
pullingdown (threshold) {
if ( !this.pulldownOptionsSync.show ) {
return
}
if ( this.pulldownStatus != 'end' ) {
// #ifndef APP-NVUE
if ( threshold >= 120 ) {
this.pulldownStatus = 'ready'
} else {
this.pulldownStatus = ''
}
// #endif
// #ifdef APP-NVUE
if ( threshold >= 195 ) {
this.pulldownStatus = 'ready'
} else {
this.pulldownStatus = ''
}
// #endif
}
this.$emit('pullingdown', threshold)
},
pullingup (threshold) {
this.$emit('pullingup', threshold)
},
resetPulldownIns () {
this.pulldownTimer = setTimeout(() => {
if ( this.pulldownStatus != 'end' ) {
this.pulldownStatus = ''
}
this.pulldownRestore = false
clearTimeout(this.pulldownTimer)
this.pulldownTimer = null
}, this.pulldownOptionsSync.duration)
},
resetPulldown () {
this.pulldownStatus = ''
}
}
}
\ No newline at end of file
<template>
<view class="yb-pulldown yb-flex yb-align-center yb-justify-center"
:class="{
'yb-row': options.row
}" v-if="options.show">
<view class="yb-flex yb-align-center yb-justify-center" :style="{'margin-left': options.row ? '-70rpx' : 0}">
<view class="yb-flex indicator-icon yb-align-center yb-justify-center">
<template v-if="status == 'ready' || status == ''">
<view class="yb-flex indicator-symbol"
:style="{
'transform': 'rotateZ(' + (status == 'ready' ? '180deg' : 0) + ')'
}">
<slot name="pulldown-symbol">
<list-icon
name="arrow-down"
:size="50"
:color="options.color"></list-icon>
</slot>
</view>
</template>
<template v-if="status == 'loading'">
<slot name="pulldown-loading">
<list-loading :visible="status == 'loading'" :color="options.color"></list-loading>
</slot>
</template>
<template v-if="status == 'success'">
<slot name="pulldown-success">
<list-icon
name="hook-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
<template v-if="status == 'fail'">
<slot name="pulldown-fail">
<list-icon
name="fork-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
<template v-if="status == 'end'">
<slot name="pulldown-end">
<list-icon
name="hook-circle"
:size="50"
:color="options.color"></list-icon>
</slot>
</template>
</view>
</view>
<view class="yb-flex indicator-text yb-align-center">
<text class="refresh-text" :style="{color: options.color}">{{pulldownText}}</text>
<text class="refresh-time" :style="{color: options.color}" v-if="options.enableRefreshTime">上次更新 {{lastTime}}</text>
</view>
</view>
</template>
<script>
import Util from '@/uni_modules/yingbing-ReadPage/js_sdk/util.js'
import ListIcon from '../common/icon.vue'
import ListLoading from '../common/loading.vue'
export default {
components: {
ListIcon,
ListLoading
},
props: {
options: {
type: Object,
default () {
return new Object
}
},
status: {
type: String,
default: ''
}
},
data () {
return {
lastTime: '刷新时间'
}
},
computed: {
pulldownText () {
return this.status == 'ready' ? this.options.readyText : this.status == 'loading' ? this.options.refreshingText : this.status == 'success' ? this.options.successText : this.status == 'fail' ? this.options.failText : this.status == 'end' ? this.options.endText : this.options.defaultText
}
},
mounted() {
this.lastTime = this.getTime()
},
methods: {
getTime () {
let d = new Date()
return (d.getMonth() + 1) + '-' + d.getDate() + ' ' + Util.zeroize(d.getHours()) + ':' + Util.zeroize(d.getMinutes())
}
},
watch: {
status (newVal) {
if ( newVal == 'success' || newVal == 'fail' ) {
this.lastTime = this.getTime()
}
}
}
}
</script>
<style scoped>
@import url(@/uni_modules/yingbing-ReadPage/css/common.css);
.yb-pulldown .indicator-icon {
width: 70rpx;
height: 70rpx;
}
.yb-pulldown .refresh-text {
text-align: center;
font-size: 24rpx;
}
.yb-pulldown .indicator-symbol {
transition: transform .1s;
}
.yb-pulldown .refresh-time {
font-size: 23rpx;
}
</style>
\ No newline at end of file
var max = 200
function touchstart(event, ins) {
var state = ins.getState()
if ( !state.enablePulldown ) {
return
}
var touch = event.touches[0] || event.changedTouches[0]
state.startX = touch.pageX
state.startY = touch.pageY
}
function touchmove(event, ins) {
var state = ins.getState()
if ( state.startY > 0) {
var touch = event.touches[0] || event.changedTouches[0]
if ((Math.abs(touch.pageY - state.startY) > Math.abs(touch.pageX - state.startX)) && Math.abs(touch.pageY -
state.startY) > 20) {
var pageY = touch.pageY
var rate = max / (max + Math.abs(pageY - state.startY))
state.threshold = rate * (pageY - state.startY)
if ( state.threshold > max ) {
state.threshold = max
}
if ( state.threshold < -max ) {
state.threshold = -max
}
ins.selectComponent('.yb-pulldown-scroller').setStyle({
transform: 'translateY(' + state.threshold + 'px)',
transition: ''
})
ins.selectComponent('.yb-list-pulldown').setStyle({
transform: 'translateY(' + state.threshold + 'px)',
transition: ''
})
if ( state.threshold > 0 ) {
ins.callMethod('pullingdown', state.threshold)
} else {
ins.callMethod('pullingup', Math.abs(state.threshold))
}
}
}
}
function touchend(event, ins) {
var state = ins.getState()
if ( state.threshold > 120 && state.enablePulldown ) {
ins.selectComponent('.yb-pulldown-scroller').setStyle({
transform: 'translateY(120px)',
transition: 'transform .1s'
})
ins.selectComponent('.yb-list-pulldown').setStyle({
transform: 'translateY(120px)',
transition: 'transform .1s'
})
ins.callMethod('refresh')
} else {
ins.selectComponent('.yb-pulldown-scroller').setStyle({
transform: 'translateY(0)',
transition: 'transform .1s'
})
ins.selectComponent('.yb-list-pulldown').setStyle({
transform: 'translateY(0)',
transition: 'transform .1s'
})
}
}
function stop (ins) {
var state = ins.getState()
ins.selectComponent('.yb-pulldown-scroller').setStyle({
transform: 'translateY(0)',
transition: 'transform .1s'
})
ins.selectComponent('.yb-list-pulldown').setStyle({
transform: 'translateY(0)',
transition: 'transform .1s'
})
state.threshold = 0
state.startY = 0
ins.callMethod('resetPulldownIns')
}
function propWatcher (newVal, oldVal, ins) {
ins.setTimeout(function () {
var state = ins.getState()
state.enablePulldown = (newVal && newVal.enablePulldown)
if ( (newVal && newVal.pulldownRestore) != (oldVal && oldVal.pulldownRestore) ) {
if ( newVal.pulldownRestore ) {
stop(ins)
}
}
}, 100)
}
module.exports = {
propWatcher: propWatcher,
touchstart: touchstart,
touchmove: touchmove,
touchend: touchend
}
\ No newline at end of file
export default {
methods: {
computedNochapter (data) {
const reg = new RegExp(/(第+[一二两三四五六七八九十○零百千万亿0-91234567890※✩★☆]{1,6}[章回卷节折篇幕集部]?[、.-\s][^\n]*)[_,-]?/g)
let match = ''
let catalog = []
let chapter = 0
let content = data.content
while ((match = reg.exec(content)) != null) {
chapter++
if ( chapter == 1 && match.index > 0 ) {
catalog.push({
title: content.slice(0, 10).replace(/[\r\n\t]/g, ''),
start: 0,
end: match.index,
content: content.slice(0, match.index),
isStart: true,
isEnd: false,
chapter: chapter
})
chapter++
}
catalog.push({
title: match[0].replace(/[\r\n\t]/g, '').slice(0, 10),
start: match.index,
isStart: false,
isEnd: false,
chapter: chapter
})
if ( chapter > 1 && !catalog[chapter-2].content ) {
catalog[chapter-2].content = content.slice(catalog[chapter-2].start, match.index)
catalog[chapter-2].end = match.index
}
}
if ( catalog.length == 1 ) {
catalog[0].content = content
catalog[0].end = content.length
}
if ( catalog.length > 0 ) {
catalog[0].isStart = true
catalog[catalog.length-1].isEnd = true
catalog[catalog.length-1].content = content.slice(catalog[catalog.length-1].start)
catalog[catalog.length-1].end = content.length
}
if ( data.content.length / catalog.length <= 10000 ) {
this.contents = catalog
if (catalog[catalog.length-1].content.length > 50000) {
let lastContent = catalog[catalog.length-1].content
this.contents.pop()
this.cutChapter({
content: lastContent,
currentChapter: data.currentChapter,
start: data.start
}, 0, 3000)
} else {
this.initLoading = true;
this.resetPage({
start: parseInt(data.start || 0),
currentChapter: parseInt(data.currentChapter),
title: data.title || null
});
this.$emit('setCatalog', this.contents)
}
} else {
this.contents = []
this.cutChapter(data, 0, 3000)
}
},
//分割章节
cutChapter (data, start, length) {
let end = start + length
let str = data.content.slice(start, end)
let index1 = str.lastIndexOf('\r')
let index2 = str.lastIndexOf('\n')
let index = Math.max(index1, index2)
index > -1 ? str = str.slice(0, index+1) : null
end = start + str.length
let chapter = this.contents.length + 1
this.contents.push({
title: '第' + chapter + '节 ' + str.replace(/[\r\n\t\s]/g, '').slice(0, 10),
chapter: chapter,
isStart: false,
isEnd: false,
start: start,
end: end,
content: str
})
if ( end < data.content.length ) {
this.cutChapter(data, end, length)
} else {
this.contents[0].isStart = true
this.contents[this.contents.length-1].isEnd = true
this.initLoading = true;
this.resetPage({
start: parseInt(data.start || 0),
currentChapter: parseInt(data.currentChapter || 1),
title: data.title || null
});
this.$emit('setCatalog', this.contents)
}
}
}
}
\ No newline at end of file
<template>
<!-- #ifndef APP-NVUE -->
<view class="read-rich-text" :style="richTextStyle" v-html="richtext">
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view class="read-rich-text" :style="richTextStyle">
<web-view
ref="webview"
@onPostMessage="onPostMessage"
:style="webviewStyle"
:src="'/uni_modules/yingbing-ReadPage/hybrid/html/richtext.html?rich=' + encodeURIComponent(JSON.stringify(richtext)) + '&pageType=' + pageType"></web-view>
</view>
<!-- #endif -->
</template>
<script>
export default {
props: {
richtext: {
type: String,
default: ''
},
pageType: {
type: String,
default: ''
},
fontFace: {
type: Array,
default () {
return new Array
}
}
},
computed: {
webviewStyle () {
return this.pageType == 'scroll' ? {
height: this.customWebviewHeight + 'px'
} : {
flex: 1
}
},
richTextStyle () {
return this.pageType == 'scroll' ? {
'padding-bottom': '20rpx'
} : {
flex: 1
}
}
},
data () {
return {
customWebviewHeight: 0
}
},
mounted() {
// #ifdef APP-NVUE
if ( this.fontFace.length > 0 ) {
this.$nextTick(function () {
setTimeout(() => {
this.setFontFace()
}, 100)
})
}
// #endif
},
methods: {
onPostMessage (e) {
e.detail.data.forEach(item => {
if ( item.customClick ) {
this.$emit('customClick', item.customClick)
}
if ( item.height ) {
this.customWebviewHeight = item.height
}
})
},
setFontFace () {
this.$refs.webview && this.$refs.webview.evalJS("setFontFace(" + encodeURIComponent(JSON.stringify(this.fontFace)) + ")")
}
},
watch: {
FontFace (newVal) {
if ( newVal.length > 0 ) {
this.$nextTick(function () {
setTimeout(() => {
this.setFontFace()
}, 100)
})
}
}
}
}
</script>
<style scoped>
.read-rich-text {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
/* #endif */
}
</style>
\ No newline at end of file
.yingbing-scroll {
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 */
}
.scroll-wrapper {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
/* #endif */
flex: 1;
}
.scroll-item {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
/* #endif */
}
.scroll-item-content {
/* #ifndef APP-NVUE */
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
/* #endif */
padding-bottom: 20rpx;
}
.scroll-text {
/* #ifndef APP-NVUE */
box-sizing: border-box;
white-space: pre-wrap;
/* #endif */
}
.scroll-item-header {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
overflow: hidden;
/* #endif */
padding: 0 40rpx;
position: fixed;
left: 20rpx;
align-items: center;
flex-direction: row;
justify-content: space-between;
height: 50rpx;
background-color: rgba(0,0,0,.4);
border-radius: 50rpx;
}
.scroll-item-header-text {
font-size: 24rpx;
color: #fff;
/* #ifdef APP-NVUE */
lines: 1;
text-overflow: ellipsis;
/* #endif */
/* #ifndef APP-NVUE */
display: -webkit-box !important;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
-webkit-box-orient:vertical;
-webkit-line-clamp: 1;
/* #endif */
}
.scroll-item-footer {
/* #ifndef APP-NVUE */
display: flex;
box-sizing: border-box;
overflow: hidden;
/* #endif */
padding: 0 40rpx;
position: fixed;
left: 20rpx;
right: 20rpx;
align-items: center;
flex-direction: row;
justify-content: space-between;
height: 50rpx;
background-color: rgba(0,0,0,.4);
border-radius: 50rpx;
}
.scroll-item-footer-text {
font-size: 24rpx;
color: #fff;
}
\ No newline at end of file
import Util from '../../../js_sdk/util.js'
export default {
data () {
return {
pageTo: 0,
scrollTop: 0,
scrolling: false,
scrollDate: ''
}
},
beforeDestroy() {
if ( this.scrollTimer ) {
clearTimeout(this.scrollTimer)
this.scrollTimer = null
}
},
mounted () {
this.scrollDate = this.filterDate()
},
methods: {
scrollNext () {
if ( this.scrolling ) {
return
}
this.scrolling = true
this.$refs.list.scrollTo(this.scrollTop + (this.windowHeight / 2), true)
this.scrollTimer = setTimeout(() => {
this.scrolling = false
clearTimeout(this.scrollTimer)
this.scrollTimer = null
}, 300)
},
scrollPrev () {
if ( this.scrolling ) {
return
}
this.scrolling = true
this.$refs.list.scrollTo(this.scrollTop - (this.windowHeight / 2), true)
this.scrollTimer = setTimeout(() => {
this.scrolling = false
clearTimeout(this.scrollTimer)
this.scrollTimer = null
}, 300)
},
pulldownScroll (callback) {
let contentsIndex = this.contents.findIndex(content => content.chapter == this.pages[0].chapter)
if ( this.contents[contentsIndex].isStart ) {
callback('end')
} else {
this.scroll_loadmore({
chapter: this.pages[0].chapter - 1,
type: 'prev'
}, callback)
this.$refs.list.resetLoadmore()
}
},
scrolltoupper () {
let contentsIndex = this.contents.findIndex(content => content.chapter == (this.pages[0].chapter - 1))
if ( contentsIndex > -1 ) {
this.scroll_loadmore({
chapter: this.pages[0].chapter - 1,
type: 'prev'
})
this.$refs.list.resetLoadmore()
}
},
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')
} else {
this.scroll_loadmore({
chapter: this.pages[this.pages.length - 1].chapter + 1,
type: 'next'
}, callback)
this.$refs.list.resetPulldown()
}
},
//加载更多章节
scroll_loadmore (load, callback) {
const chapter = load.chapter;
const type = load.type;
const contentIndex = this.contents.findIndex(item => item.chapter == chapter);
if ( contentIndex > -1 ) {
this.computedPage({
content: this.contents[contentIndex],
type: type
});
this.preload(chapter)
callback && callback('success')
} else {
this.$emit('loadmore', chapter, (status, content) => {
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.computedPage({
content: content,
type: type
});
this.preload(chapter)
}
callback && callback(status)
})
}
},
async scrollEnd(e) {
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
while ( top < 0 ) {
let rect = await this.getScrollItemRect(this.pages[maybe].dataId)
top = rect.top
pageInfo = this.pages[maybe]
maybe++
}
if ( top >= 0 ) {
const nowChapters = this.pages.filter(item => item.chapter == pageInfo.chapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot'))
let contentIndex = this.contents.findIndex(content => content.chapter == pageInfo.chapter)
pageInfo.totalPage = nowChapters.length
pageInfo.currentPage = nowChapters.findIndex(item => item.dataId == pageInfo.dataId) + 1
this.pageInfo = pageInfo
//刷新当前时间和设备电量
this.scrollDate = this.filterDate()
this.$refs.scrollBattery.getBattery()
this._emitPageInfo(pageInfo, this.pages)
this.startAutoplay()
}
},
getScrollItemRect (dataId) {
return new Promise(resolve => {
Util.getRect('#scroll-item_' + dataId, Util.getRefs(this, 'scrollItem_' + dataId, 0), this).then(res => {
resolve(res)
})
})
},
onScroll (e) {
this.stopAutoplay()
if ( this.options.pageType == 'scroll' ) {
this.scrollTop = e.scrollTop
if ( this.scrollTimer ) {
clearTimeout(this.scrollTimer)
this.scrollTimer = null
}
this.scrollTimer = setTimeout(() => {
this.scrolling = false
this.scrollEnd(e)
}, 300)
}
}
}
}
\ No newline at end of file
.yb-flex {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
flex-shrink: 0;
background: none;
flex-wrap: nowrap;
/* #endif */
}
.yb-flex-1 {
flex: 1!important;
}
.yb-wrap {
flex-wrap: wrap!important;
}
.yb-row {
flex-direction: row!important;
}
.yb-column {
flex-direction: column!important;
}
.yb-row-reverse {
flex-direction: row-reverse!important;
}
.yb-column-reverse {
flex-direction: column-reverse!important;
}
.yb-align-center {
align-items: center!important;
}
.yb-align-start {
align-items: flex-start!important;
}
.yb-align-end {
align-items: flex-end!important;
}
.yb-align-between {
align-content: space-between!important;
}
.yb-justify-center {
justify-content: center!important;
}
.yb-justify-start {
justify-content: flex-start!important;
}
.yb-justify-end {
justify-content: flex-end!important;
}
.yb-justify-between {
justify-content: space-between!important;
}
/* #ifdef MP */
.scoped-ref {
display: flex;
flex-direction: column;
box-sizing: border-box;
overflow: hidden;
flex-shrink: 0;
background: none;
flex-wrap: nowrap;
flex: 1;
}
.yb-tap view:nth-child(n+2) {
position: relative;
}
.yb-tap text:nth-child(n+1) {
position: relative;
}
/* #endif */
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function r(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}var o=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(r()){if("postMessage"===e){var o={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(o):window.__dcloud_weex_.postMessage(JSON.stringify(o))}var a={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(a):window.__dcloud_weex_.postMessageToService(JSON.stringify(a))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var d=plus.webview.currentWebview();if(!d)throw new Error("plus.webview.currentWebview() is undefined");var s=d.parent(),w="";w=s?s.id:d.id,t.push(w)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var u=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(u,",").concat(JSON.stringify(t),");"))}},a={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;o("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;o("redirectTo",{url:encodeURI(n)})},getEnv:function(e){r()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};o("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf(["t","n","e","i","l","C","y","a","p","i","l","A"].reverse().join(""))>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var v=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var c=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var E=window.xhs&&window.xhs.miniProgram&&/xhsminiapp/i.test(navigator.userAgent);for(var h,P=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},b=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(v)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(c)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){if(E)return window.xhs.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y<b.length&&!(h=b[y](P));y++);h||(h={});var B="undefined"!=typeof uni?uni:{};if(!B.navigateTo)for(var S in h)i(h,S)&&(B[S]=h[S]);return B.webView=h,B}));
\ No newline at end of file
<html>
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<title>富文本展示</title>
<style type="text/css">
html,body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.content {
color: #333;
width: 100%;
height: 100%;
}
.content img {
max-width: 100%!important;
}
</style>
</head>
<body>
<p id="content" class="content"></p>
</body>
<script type="text/javascript" src="./js/uni-webview-js@1.5.4.js"></script>
<script type="text/javascript">
var obj = {}
window.onload = function () {
var search = window.location.search.slice(1);
var arr = search.split('&');
for ( var i = 0; i < arr.length; i++ ) {
var strs = arr[i].split('=');
obj[strs[0]] = strs[1];
}
if ( obj.rich ) {
setRichText(JSON.parse(decodeURIComponent(obj.rich)));
if ( obj.pageType == 'scroll' ) {
window.setTimeout(function () {
uni.postMessage({
data: {
height: document.getElementById('content').scrollHeight + 100
}
});
}, 100)
}
}
}
function setStyle (attribute, value) {
document.getElementById('content').style[attribute] = value
}
function setRichText (richText) {
document.getElementById('content').innerHTML = richText
}
function setFontFace (fontList) {
let code = fontList.reduce((accumulator, currentValue) => {
return accumulator + `@font-face { font-family: ${currentValue.fontFamily};src: url('${currentValue.src}'); }`;
}, "");
var style = document.createElement("style");
style.type = "text/css";
style.rel = "stylesheet";
style.appendChild(document.createTextNode(code));
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
function triggerCustomClick (name, args) {
uni.postMessage({
data: {
customClick: {
name: name,
args: args
}
}
});
}
</script>
</html>
\ No newline at end of file
This diff is collapsed.
{
"id": "yingbing-ReadPage",
"displayName": "好用阅读分页插件",
"version": "1.6.0",
"description": "给小说分页的插件",
"keywords": [
"小说",
"阅读",
"翻页",
"分页"
],
"repository": "https://gitee.com/yingbing-developer/yingbing-read-page.git",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": "1014295211"
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "n",
"IE": "n",
"Edge": "n",
"Firefox": "n",
"Safari": "n"
},
"小程序": {
"微信": "y",
"阿里": "n",
"百度": "n",
"字节跳动": "n",
"QQ": "n"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "u"
}
}
}
}
}
## 1.0.4(2023-09-02)
* 解决插槽中有scroll-view等滚动组件时滑动报错的问题
## 1.0.3(2023-08-23)
* 解决APP-NVUE端resetLoading不生效的问题
## 1.0.2(2023-07-25)
* 解决竖直翻页时,点击上下2侧翻页不准确得问题
## 1.0.1(2023-07-24)
* 解决APP-NVUE无法点击左右2侧翻页得问题
## 1.0.0(2023-07-22)
* 第一次更新
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment