<template>
							 | 
						|
									<view class="yingbing-reader" ref="yingbingReader" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
							 | 
						|
										<view class="yingbing-scroll-reader" :class="{'yingbing-hidden': pageType != 'scroll'}" :style="[wrapperStyle]">
							 | 
						|
											<reader-header :progress="currentProgress" :title="currentTitle" v-if="headerShow && currentTitle"></reader-header>
							 | 
						|
											<view class="yingbing-scroll yingbing-reader-content" ref="yingbingReaderContent">
							 | 
						|
												<reader-scroller
							 | 
						|
												ref="scroll"
							 | 
						|
												:autoplay="autoplaySync"
							 | 
						|
												:loadmoreable="!isLoading && !autoplaySync && pages.length > 0"
							 | 
						|
												:pulldownable="!isLoading && !autoplaySync"
							 | 
						|
												@pulldown="handlePulldown"
							 | 
						|
												@loadmore="handlePullup"
							 | 
						|
												@scroll="handleScroll"
							 | 
						|
												:data="pageType == 'scroll' ? pages : []">
							 | 
						|
													<!-- #ifndef MP-->
							 | 
						|
													<template v-slot="{item, index}">
							 | 
						|
													<!-- #endif -->
							 | 
						|
													<!-- #ifdef MP -->
							 | 
						|
													<template v-for="(item, index) in pages" :slot="`wx:${index}`">
							 | 
						|
													<!-- #endif -->
							 | 
						|
														<view :style="{position: 'relative', 'height': contentHeight + 'px'}" v-if="item.type == 'slot' && pageType == 'scroll'">
							 | 
						|
															<!-- 微信小程序vue2虽然支持在v-for中嵌套同名插槽,但会一直报错,引起页面卡顿,vue3不支持在v-for中嵌套同名插槽,所以增加2种微信小程序使用方式 -->
							 | 
						|
															<!-- #ifdef MP -->
							 | 
						|
															<slot :name="item.content + ':' + item.index"></slot>
							 | 
						|
															<!-- #endif -->
							 | 
						|
															<!-- #ifndef MP -->
							 | 
						|
															<slot :name="item.content" :item="item" :index="index"></slot>
							 | 
						|
															<!-- #endif -->
							 | 
						|
														</view>	
							 | 
						|
														<read-content :item="item" v-if="item.type == 'text'"></read-content>
							 | 
						|
														<view class="yingbing-reader-content-loading" :style="{'height': contentHeight + 'px'}" v-if="item.type == 'error'" @touchstart.stop.prevent @touchmove.stop.prevent @touchend.stop.prevent="handleReload(item)">
							 | 
						|
															<text class="yingbing-reader-content-loading-text" :style="{color: color}">{{errorText}}</text>
							 | 
						|
														</view>
							 | 
						|
														<view class="yingbing-reader-content-loading" :style="{'height': contentHeight + 'px'}" v-if="item.type == 'loading'">
							 | 
						|
															<reader-loading size="20px" :color="color || ''"></reader-loading>
							 | 
						|
															<text class="yingbing-reader-content-loading-text" :style="{color: color}">{{loadingText}}</text>
							 | 
						|
														</view>
							 | 
						|
													</template>
							 | 
						|
												</reader-scroller>
							 | 
						|
											</view>	
							 | 
						|
											<reader-footer ref="footer" :total="currentTotal" :current="currentPage" v-if="footerShow && currentTotal"></reader-footer>
							 | 
						|
										</view>
							 | 
						|
										<yingbing-flip
							 | 
						|
										:class="{'yingbing-hidden': pageType == 'scroll'}"
							 | 
						|
										class="yingbing-flip-reader yingbing-reader-absolute"
							 | 
						|
										ref="flip"
							 | 
						|
										:autoplay="autoplaySync"
							 | 
						|
										:interval="interval"
							 | 
						|
										:current="current"
							 | 
						|
										:type="pageType"
							 | 
						|
										:data="pageType != 'scroll' ? pages : []"
							 | 
						|
										:background="background"
							 | 
						|
										:duration="300"
							 | 
						|
										:unableClickPage="unableClickPage"
							 | 
						|
										:pulldownable="!isLoading"
							 | 
						|
										:pullupable="!isLoading"
							 | 
						|
										@change="handleChange"
							 | 
						|
										@pulldown="handlePulldown"
							 | 
						|
										@pullup="handlePullup">
							 | 
						|
											<!-- #ifndef MP-->
							 | 
						|
											<template v-slot="{item, index}">
							 | 
						|
											<!-- #endif -->
							 | 
						|
											<!-- #ifdef MP -->
							 | 
						|
											<template v-for="(item, index) in pages" :slot="`wx:${index}`">
							 | 
						|
											<!-- #endif -->
							 | 
						|
												<view class="yingbing-reader-absolute yingbing-flip-reader-wrapper" :style="[wrapperStyle]">
							 | 
						|
													<reader-header :progress="item.progress" :title="item.title || title" v-if="getFlipHeaderShow(item)"></reader-header>
							 | 
						|
													<view class="yingbing-flip-reader-content">
							 | 
						|
														<template v-if="item.type == 'slot' && pageType != 'scroll'">
							 | 
						|
															<!-- 微信小程序vue2虽然支持在v-for中嵌套同名插槽,但会一直报错,引起页面卡顿,vue3不支持在v-for中嵌套同名插槽,所以增加2种微信小程序使用方式 -->
							 | 
						|
															<!-- #ifdef MP -->
							 | 
						|
															<slot :name="item.content + ':' + item.index"></slot>
							 | 
						|
															<!-- #endif -->
							 | 
						|
															<!-- #ifndef MP -->
							 | 
						|
															<slot :name="item.content" :item="item" :index="index"></slot>
							 | 
						|
															<!-- #endif -->
							 | 
						|
														</template>
							 | 
						|
														<read-content class="yingbing-reader-absolute" :item="item" v-if="item.type == 'text'"></read-content>
							 | 
						|
														<view class="yingbing-reader-absolute yingbing-reader-content-loading" v-if="item.type == 'error'" @touchstart.stop.prevent @touchmove.stop.prevent @touchend.stop.prevent="handleReload(item)">
							 | 
						|
															<text class="yingbing-reader-content-loading-text" :style="{color: color}">{{errorText}}</text>
							 | 
						|
														</view>
							 | 
						|
														<view class="yingbing-reader-absolute yingbing-reader-content-loading" v-if="item.type == 'loading'">
							 | 
						|
															<reader-loading size="20px" :color="color || ''"></reader-loading>
							 | 
						|
															<text class="yingbing-reader-content-loading-text" :style="{color: color}">{{loadingText}}</text>
							 | 
						|
														</view>
							 | 
						|
													</view>
							 | 
						|
													<reader-footer :total="item.total" :current="item.current" v-if="getFlipFooterShow(item)"></reader-footer>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pulldownDefault>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPulldownEnd ? prevChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : prevChapterDefaultText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pulldownReady>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPulldownEnd ? prevChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterReadyText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pulldownLoading>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPulldownEnd ? prevChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterLoadingText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pulldownSuccess>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPulldownEnd ? prevChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterSuccessText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pulldownFail>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPulldownEnd ? prevChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterFailText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pullupDefault>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPullupEnd ? nextChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : nextChapterDefaultText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pullupReady>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPullupEnd ? nextChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterReadyText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pullupLoading>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPullupEnd ? nextChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterLoadingText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pullupSuccess>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPullupEnd ? nextChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterSuccessText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
											<template #pullupFail>
							 | 
						|
												<view class="loading-box">
							 | 
						|
													<text class="loading-text">{{isPullupEnd ? nextChapterEndText.split('').join('\n') : chapterLoading ? chapterLoadingText.split('').join('\n') : chapterFailText.split('').join('\n') }}</text>
							 | 
						|
												</view>
							 | 
						|
											</template>
							 | 
						|
										</yingbing-flip>
							 | 
						|
										<!-- 循环computed计算组件,避免计算冲突 -->
							 | 
						|
										<computed
							 | 
						|
										:window-width="windowWidth"
							 | 
						|
										:window-height="windowHeight"
							 | 
						|
										ref="computed" v-for="(c, i) in computeds"
							 | 
						|
										:key="c"></computed>
							 | 
						|
									</view>
							 | 
						|
								</template>
							 | 
						|
								
							 | 
						|
								<script>
							 | 
						|
									// #ifdef H5 || MP-WEIXIN
							 | 
						|
									import ReadContent from './h5/content.vue'
							 | 
						|
									import Computed from './h5/computed.vue'
							 | 
						|
									// #endif
							 | 
						|
									// #ifdef APP-VUE
							 | 
						|
									import Computed from './app-vue/computed.vue'
							 | 
						|
									import ReadContent from './h5/content.vue'
							 | 
						|
									// #endif
							 | 
						|
									import ReaderLoading from '../loading/loading.vue'
							 | 
						|
									import ReaderHeader from '../header/header.vue'
							 | 
						|
									import ReaderFooter from '../footer/footer.vue'
							 | 
						|
									import ReaderScroller from '../scroller/scroller.vue'
							 | 
						|
									import FlipReaderMixin from './flip-reader.js'
							 | 
						|
									import ScrollReaderMixin from './scroll-reader.js'
							 | 
						|
									import TouchClickMixin from '../mixin/touch-click.js'
							 | 
						|
									import TipMixin from '../mixin/tip.js'
							 | 
						|
									const threshold  = 50//点击事件阙值
							 | 
						|
									export default {
							 | 
						|
										options: {
							 | 
						|
											addGlobalClass: true,
							 | 
						|
											virtualHost: true,  //  将自定义节点设置成虚拟的,更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
							 | 
						|
										},
							 | 
						|
										mixins: [FlipReaderMixin, ScrollReaderMixin, TouchClickMixin, TipMixin],
							 | 
						|
										components: {
							 | 
						|
											ReadContent,
							 | 
						|
											ReaderHeader,
							 | 
						|
											ReaderFooter,
							 | 
						|
											ReaderLoading,
							 | 
						|
											ReaderScroller,
							 | 
						|
											Computed
							 | 
						|
										},
							 | 
						|
										provide () {
							 | 
						|
											return {
							 | 
						|
												getColor: () => this.color,
							 | 
						|
												getFontSize: () => this.fontSize,
							 | 
						|
												getFontFamily: () => this.fontFamily,
							 | 
						|
												getLineHeight: () => this.lineHeightSync,
							 | 
						|
												getTopGap: () => this.topGap,
							 | 
						|
												getBottomGap: () => this.bottomGap,
							 | 
						|
												getSlide: () => this.slide,
							 | 
						|
												getHeaderShow: () => this.headerShow,
							 | 
						|
												getFooterShow: () => this.footerShow,
							 | 
						|
												getBackShow: () => this.backShow,
							 | 
						|
												getSplit: () => this.split,
							 | 
						|
												getTotalChapter: () => this.totalChapter,
							 | 
						|
												getSelectable: () => this.selectable,
							 | 
						|
												getPageType: () => this.pageType,
							 | 
						|
												getMeasureSize: () => this.measureSize,
							 | 
						|
												getCharSize: () => this.charSize
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										props: {
							 | 
						|
											//自动翻页/滚动
							 | 
						|
											autoplay: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: false
							 | 
						|
											},
							 | 
						|
											//自动翻页/滚动周期
							 | 
						|
											interval: {
							 | 
						|
												type: [String, Number],
							 | 
						|
												default: 5000
							 | 
						|
											},
							 | 
						|
											//字体颜色
							 | 
						|
											color: {
							 | 
						|
												type: String,
							 | 
						|
												default: '#333333'
							 | 
						|
											},
							 | 
						|
											//字体大小(单位px)
							 | 
						|
											fontSize: {
							 | 
						|
												type: [String, Number],
							 | 
						|
												default: 15
							 | 
						|
											},
							 | 
						|
											//行高(单位px)
							 | 
						|
											lineHeight: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: ''
							 | 
						|
											},
							 | 
						|
											//页面左右边距(单位px)
							 | 
						|
											slide: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: 20
							 | 
						|
											},
							 | 
						|
											//页面上边距(单位px)
							 | 
						|
											topGap: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: 10
							 | 
						|
											},
							 | 
						|
											//页面下边距(单位px)
							 | 
						|
											bottomGap: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: 10
							 | 
						|
											},
							 | 
						|
											//展示头部
							 | 
						|
											headerShow: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: true
							 | 
						|
											},
							 | 
						|
											//展示底部
							 | 
						|
											footerShow: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: true
							 | 
						|
											},
							 | 
						|
											//展示返回图标
							 | 
						|
											backShow: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: false
							 | 
						|
											},
							 | 
						|
											//总章节数量 用于计算进度
							 | 
						|
											totalChapter: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: 0
							 | 
						|
											},
							 | 
						|
											//字体名称
							 | 
						|
											fontFamily: {
							 | 
						|
												type: String,
							 | 
						|
												default: 'Arial'
							 | 
						|
											},
							 | 
						|
											//背景颜色
							 | 
						|
											background: {
							 | 
						|
												type: String,
							 | 
						|
												default: '#fcd281'
							 | 
						|
											},
							 | 
						|
											//开启预加载
							 | 
						|
											preloadable: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: false
							 | 
						|
											},
							 | 
						|
											//开启文本选择
							 | 
						|
											selectable: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: false
							 | 
						|
											},
							 | 
						|
											//还剩多少页时,开始加载下一章节
							 | 
						|
											loadPageNum: {
							 | 
						|
												type: [Number, String],
							 | 
						|
												default: 4
							 | 
						|
											},
							 | 
						|
											//是否关闭点击左右2侧位置翻页
							 | 
						|
											unableClickPage: {
							 | 
						|
												type: Boolean,
							 | 
						|
												default: false
							 | 
						|
											},
							 | 
						|
											//翻页方式
							 | 
						|
											pageType: {
							 | 
						|
												type: String,
							 | 
						|
												default: 'scroll'
							 | 
						|
											},
							 | 
						|
											//分隔符
							 | 
						|
											split: {
							 | 
						|
												type: String,
							 | 
						|
												default: ''
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										computed: {
							 | 
						|
											//行高计算
							 | 
						|
											lineHeightSync () {
							 | 
						|
												return this.lineHeight || (parseInt(this.fontSize) + 15)
							 | 
						|
											},
							 | 
						|
											wrapperStyle () {
							 | 
						|
												return {
							 | 
						|
													'padding-top': this.topGap + 'px',
							 | 
						|
													'padding-bottom': this.bottomGap + 'px',
							 | 
						|
													'background': this.background,
							 | 
						|
													'padding-left': this.slide + 'px',
							 | 
						|
													'padding-right': this.slide + 'px'
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//是否正在初始化或者跳转章节内容
							 | 
						|
											isLoading () {
							 | 
						|
												return this.pages.some(p => p.type == 'loading')
							 | 
						|
											},
							 | 
						|
											//是否渲染到第一章
							 | 
						|
											isPulldownEnd () {
							 | 
						|
												return this.pages.findIndex(c => c.isStart) > -1
							 | 
						|
											},
							 | 
						|
											//是否渲染到最后一章
							 | 
						|
											isPullupEnd () {
							 | 
						|
												return this.pages.findIndex(c => c.isEnd) > -1
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										data () {
							 | 
						|
											return {
							 | 
						|
												computeds: [],//计算集合,为了避免计算冲突
							 | 
						|
												pages: [],//渲染页面集合
							 | 
						|
												chapters: [],//章节列表集合
							 | 
						|
												chapterLoading: false,//章节请求loading
							 | 
						|
												current: 0,//当前页面索引
							 | 
						|
												title: '',//小说标题
							 | 
						|
												contentHeight: 0//内容区域高度
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										beforeDestroy () {
							 | 
						|
											this.abort()
							 | 
						|
											uni.$off('yingbing-reader-back')//清楚back监听
							 | 
						|
										},
							 | 
						|
										beforeCreate() {
							 | 
						|
											uni.$on('yingbing-reader-back', () => {
							 | 
						|
												this.$emit('back')
							 | 
						|
											})
							 | 
						|
										},
							 | 
						|
										methods: {
							 | 
						|
											//翻往上一页
							 | 
						|
											prev () {
							 | 
						|
												if ( this.current <= 0 ) {
							 | 
						|
													uni.showToast({
							 | 
						|
														title: '前面没有了',
							 | 
						|
														icon: 'none'
							 | 
						|
													})
							 | 
						|
													return
							 | 
						|
												}
							 | 
						|
												this.$refs.scroll && this.$refs.scroll.scrollToIndex(this.current - 1, true)//滚动模式
							 | 
						|
												this.$refs.flip && this.$refs.flip.flipToPrev()//翻页模式
							 | 
						|
											},
							 | 
						|
											//翻往下一页
							 | 
						|
											next () {
							 | 
						|
												if ( this.current >= this.pages.length - 1 ) {
							 | 
						|
													uni.showToast({
							 | 
						|
														title: '后面没有了',
							 | 
						|
														icon: 'none'
							 | 
						|
													})
							 | 
						|
													return
							 | 
						|
												}
							 | 
						|
												this.$refs.scroll && this.$refs.scroll.scrollToIndex(this.current + 1, true)//滚动模式
							 | 
						|
												this.$refs.flip && this.$refs.flip.flipToNext()//翻页模式
							 | 
						|
											},
							 | 
						|
											//页面刷新
							 | 
						|
											refresh () {
							 | 
						|
												this.abort()
							 | 
						|
												if ( this.pages.length == 0 ) return//如果页面数量为0不做操作
							 | 
						|
												const page = this.pages[this.current]//当前页面
							 | 
						|
												const current = page.index//当前页面章节索引
							 | 
						|
												const start = page.start//当前页面开始位置
							 | 
						|
												this.refreshTimer = setTimeout(() => {
							 | 
						|
													this.render({current, start})//调用change事件
							 | 
						|
												}, 300)
							 | 
						|
											},
							 | 
						|
											//初始化
							 | 
						|
											init ({chapters, title, current, start = 0}) {
							 | 
						|
												if ( !chapters || chapters.length == 0 ) {
							 | 
						|
													uni.showToast({
							 | 
						|
														title: '至少传入一个章节内容',
							 | 
						|
														icon: 'none'
							 | 
						|
													})
							 | 
						|
													return
							 | 
						|
												}
							 | 
						|
												this.abort()
							 | 
						|
												this.autoplaySync = false//关闭自动播放
							 | 
						|
												this.title = title || ''//存储小说标题
							 | 
						|
												this.chapters = chapters//存储传入的章节内容
							 | 
						|
												// this.pages = [{index: current, type: 'loading'}]//显示loading
							 | 
						|
												setTimeout(() => {
							 | 
						|
													const chapterIndex = this.chapters.findIndex(c => c.index == current)
							 | 
						|
													if ( chapterIndex == -1 ) current = this.chapters[0].index//强制转换类型为int
							 | 
						|
													this.render({current, start})
							 | 
						|
												}, 20)
							 | 
						|
											},
							 | 
						|
											//跳转章节
							 | 
						|
											change({chapters, current, start = 0}) {
							 | 
						|
												if ( !current ) {//current必、传
							 | 
						|
													uni.showToast({
							 | 
						|
														title: 'current必传',
							 | 
						|
														icon: 'none'
							 | 
						|
													})
							 | 
						|
													return
							 | 
						|
												}
							 | 
						|
												this.abort()
							 | 
						|
												this.autoplaySync = false//关闭自动播放
							 | 
						|
												if ( chapters && chapters.length > 0 ) {//如果传入章节内容
							 | 
						|
													chapters.forEach(chapter => {
							 | 
						|
														const index = this.chapters.findIndex(c => c.index == chapter.index)//是否已经包含相同章节
							 | 
						|
														if (index > -1) this.chapters[index] = chapter//如果包含则更新
							 | 
						|
														else this.chapters.push(chapter)//否则添加新章节
							 | 
						|
													})
							 | 
						|
												}
							 | 
						|
												setTimeout(() => {
							 | 
						|
													const chapterIndex = this.chapters.findIndex(c => c.index == current)//查找对应current的章节内容
							 | 
						|
													if ( chapterIndex > -1 ) this.render({current, start})//如果过包含开始渲染内容
							 | 
						|
													else this.handleChangeLoadmore(current, start)//如果不包含,抛出loadmore事件,去获取内容
							 | 
						|
												}, 20)
							 | 
						|
											},
							 | 
						|
											async render (data) {
							 | 
						|
												const rect = await this.getRect()//获取组件尺寸
							 | 
						|
												this.windowWidth = rect.width//记录组件宽度
							 | 
						|
												this.windowHeight = rect.height//记录组件高度
							 | 
						|
												const contentRect = await this.getContentRect()//获取内容尺寸
							 | 
						|
												this.contentHeight = contentRect.height//记录内容区域高度
							 | 
						|
												if ( this.pageType == 'scroll' ) this.scrollRender(data)
							 | 
						|
												else this.flipRender(data)
							 | 
						|
											},
							 | 
						|
											//设置指定页面的内容
							 | 
						|
											setContent (index, content) {
							 | 
						|
												this.$set(this.pages[index], 'content', content)//更新页面内容
							 | 
						|
												this.$refs.flip && this.$refs.flip.forceUpdate(index)
							 | 
						|
											},
							 | 
						|
											//重加载事件
							 | 
						|
											handleReload (item) {
							 | 
						|
												this.pages = [{
							 | 
						|
													type: 'loading',
							 | 
						|
													index: item.index,
							 | 
						|
													start: item.start || undefined//记录章节定位
							 | 
						|
												}]//显示刷新效果
							 | 
						|
												this.handleChangeLoadmore(item.index, item.start)//触发loadmore
							 | 
						|
											},
							 | 
						|
											//change事件触发loadmore加载更多章节并渲染
							 | 
						|
											handleChangeLoadmore (index, start) {
							 | 
						|
												this.loadmoreFunc = (status, chapter) => {
							 | 
						|
													//请求完成后删除请求集合中的章节索引
							 | 
						|
													if (status == 'success') {//获取内容成功
							 | 
						|
														this.render({chapter, current: index, start})
							 | 
						|
													} else {
							 | 
						|
														this.pages = [{
							 | 
						|
															type: 'error',
							 | 
						|
															index: index,
							 | 
						|
															start: start || undefined//记录章节定位
							 | 
						|
														}]//显示错误页面
							 | 
						|
														this.current = 0
							 | 
						|
														this.$refs.flip && this.$refs.flip.refresh()
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
												this.$emit('loadmore', index, this.loadmoreFunc.bind(this))
							 | 
						|
											},
							 | 
						|
											//翻页改变事件
							 | 
						|
											handleChange (e) {
							 | 
						|
												this.current = e.current//记录当前定位
							 | 
						|
												this.$emit('change', e)//抛出change事件
							 | 
						|
												if ( e.current >= this.pages.length - this.loadPageNum && !this.chapterLoading ) {//如果翻到了最后loadPageNum页,并且没有加载章节
							 | 
						|
													const page = this.pages[this.pages.length-1]//回去最后页面
							 | 
						|
													if ( page.isEnd ) return
							 | 
						|
													const index = page.index + 1//
							 | 
						|
													const chapterIndex = this.chapters.findIndex(c => c.index == index)//查找对应index的章节内容
							 | 
						|
													if ( chapterIndex > -1 ) {//如果过包含开始渲染内容
							 | 
						|
														this.chapterLoading = true//开启章节加载等待
							 | 
						|
														this.handleLoadRender('success', this.chapters[chapterIndex])//渲染章节
							 | 
						|
													} else {
							 | 
						|
														if ( this.preloadable ) {//开启了预加载功能
							 | 
						|
															this.chapterLoading = true//开启章节加载等待
							 | 
						|
															this.loadmoreFunc = (status, chapter) => {//如果不包含,抛出loadmore事件,去获取内容
							 | 
						|
																this.handleLoadRender(status, chapter)//渲染章节
							 | 
						|
															}
							 | 
						|
															this.$emit('loadmore', index, this.loadmoreFunc.bind(this))
							 | 
						|
														}
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//渲染下一章节
							 | 
						|
											handleLoadRender (status, chapter, callback, isPrev) {
							 | 
						|
												if ( this.pageType == 'scroll' ) this.handleScrollLoadRender(status, chapter, callback, isPrev)
							 | 
						|
												else this.handleFlipLoadRender(status, chapter, callback, isPrev)
							 | 
						|
											},
							 | 
						|
											//上拉事件
							 | 
						|
											handlePullup (callback) {
							 | 
						|
												// if ( this.isPullupEnd || this.chapterLoading || this.isLoading  || this.current < this.pages.length - 1 ) {//如果最后页面是结束章节或者当前正在等待加载新章节或者当前页面不是最后一页则返回
							 | 
						|
												// 	callback( this.isPullupEnd && this.pageType == 'scroll' ? 'end' : 'success')//如果是滚动模式并且章节全部加载关闭则返回end否则success
							 | 
						|
												// 	return
							 | 
						|
												// }
							 | 
						|
												if ( this.pageType == 'scroll' ) {
							 | 
						|
													if ( this.isPullupEnd || this.chapterLoading || this.isLoading ) {
							 | 
						|
														callback(this.isPullupEnd ? 'end' : 'ready')
							 | 
						|
														return
							 | 
						|
													}
							 | 
						|
												} else {
							 | 
						|
													if ( this.isPullupEnd || this.chapterLoading || this.isLoading  || this.current < this.pages.length - 1 ) {//如果最后页面是结束章节或者当前正在等待加载新章节或者当前页面不是最后一页则返回
							 | 
						|
														callback('success')//如果是滚动模式并且章节全部加载关闭则返回end否则success
							 | 
						|
														return
							 | 
						|
													}
							 | 
						|
												}
							 | 
						|
												const index = this.pages[this.pages.length-1].index + 1
							 | 
						|
												const chapterIndex = this.chapters.findIndex(c => c.index == index)//查找对应index的章节内容
							 | 
						|
												this.chapterLoading = true//开启章节加载等待
							 | 
						|
												if ( chapterIndex > -1 ) {//如果过包含开始渲染内容
							 | 
						|
													this.handleLoadRender('success', this.chapters[chapterIndex], callback)//渲染章节
							 | 
						|
												} else {
							 | 
						|
													this.loadmoreFunc = (status, chapter) => {//如果不包含,抛出loadmore事件,去获取内容
							 | 
						|
														this.handleLoadRender(status, chapter, callback)//渲染章节
							 | 
						|
													}
							 | 
						|
													this.$emit('loadmore', index, this.loadmoreFunc.bind(this))
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//下拉事件
							 | 
						|
											handlePulldown (callback) {
							 | 
						|
												if ( this.isPulldownEnd || this.chapterLoading || this.isLoading ) {
							 | 
						|
													callback( this.isPullupEnd && this.pageType == 'scroll' ? 'end' : 'success')//如果是滚动模式并且章节全部加载关闭则返回end否则success
							 | 
						|
													return
							 | 
						|
												}
							 | 
						|
												const index = this.pages[0].index - 1
							 | 
						|
												const chapterIndex = this.chapters.findIndex(c => c.index == index)//查找对应index的章节内容
							 | 
						|
												this.chapterLoading = true//开启章节加载等待
							 | 
						|
												if ( chapterIndex > -1 ) {//如果过包含开始渲染内容
							 | 
						|
													this.handleLoadRender('success', this.chapters[chapterIndex], true)//渲染章节
							 | 
						|
												} else {
							 | 
						|
													this.loadmoreFunc = (status, chapter) => {//如果不包含,抛出loadmore事件,去获取内容
							 | 
						|
														this.handleLoadRender(status, chapter, callback, true)//渲染章节
							 | 
						|
													}
							 | 
						|
													this.$emit('loadmore', index, this.loadmoreFunc)
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//处理页面
							 | 
						|
											handlePages (arr) {
							 | 
						|
												arr = arr.filter(item => item.type != 'loading')//去掉加载页
							 | 
						|
												arr.sort((a, b) => a.index - b.index)//根据章节索引排序
							 | 
						|
												return arr
							 | 
						|
											},
							 | 
						|
											//清楚刷新定时器
							 | 
						|
											clearRefreshTimer () {
							 | 
						|
												if ( this.refreshTimer ) {
							 | 
						|
													clearTimeout(this.refreshTimer)
							 | 
						|
													this.refreshTimer = null
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//清楚loadmore回调
							 | 
						|
											clearLoadmoreFunc () {
							 | 
						|
												if ( this.loadmoreFunc ) this.loadmoreFunc = null
							 | 
						|
											},
							 | 
						|
											//中断正在进行的计算和请求
							 | 
						|
											abort () {
							 | 
						|
												this.clearRefreshTimer()//清空刷新定时器
							 | 
						|
												this.clearLoadmoreFunc()//清空请求回调
							 | 
						|
												this.computeds = []
							 | 
						|
											},
							 | 
						|
											//获取计算组件id
							 | 
						|
											getComputedId () {
							 | 
						|
												return (new Date().getTime() / 1000).toString() + (Math.random() * 100)
							 | 
						|
											},
							 | 
						|
											getRect () {
							 | 
						|
												return new Promise(resolve => {
							 | 
						|
													// #ifdef APP-NVUE
							 | 
						|
													uni.requireNativePlugin('dom').getComponentRect(this.$refs.yingbingReader, res => {
							 | 
						|
														resolve(res.size)
							 | 
						|
													})
							 | 
						|
													// #endif
							 | 
						|
													// #ifndef APP-NVUE
							 | 
						|
													uni.createSelectorQuery().in(this).select('.yingbing-reader').boundingClientRect(data => {
							 | 
						|
														resolve(data)
							 | 
						|
													}).exec();
							 | 
						|
													// #endif
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											//获取内容区域高度
							 | 
						|
											getContentRect () {
							 | 
						|
												return new Promise(resolve => {
							 | 
						|
													// #ifdef APP-NVUE
							 | 
						|
													uni.requireNativePlugin('dom').getComponentRect(this.$refs.yingbingReaderContent, res => {
							 | 
						|
														resolve(res.size)
							 | 
						|
													})
							 | 
						|
													// #endif
							 | 
						|
													// #ifndef APP-NVUE
							 | 
						|
													uni.createSelectorQuery().in(this).select('.yingbing-reader-content').boundingClientRect(data => {
							 | 
						|
														resolve(data)
							 | 
						|
													}).exec();
							 | 
						|
													// #endif
							 | 
						|
												})
							 | 
						|
											}
							 | 
						|
										},
							 | 
						|
										watch: {
							 | 
						|
											pageType (newVal, oldVal) {
							 | 
						|
												if ( newVal == 'scroll' ) {//当翻页模式变为滚动模式时
							 | 
						|
													this.autoplaySync = false//暂时关闭自动播放
							 | 
						|
													this.$nextTick(function () {
							 | 
						|
														this.$refs.scroll && this.$refs.scroll.scrollToIndex(this.current)//定位滚动位置
							 | 
						|
														setTimeout(() => {
							 | 
						|
															this.autoplaySync = this.autoplay//开启自动播放
							 | 
						|
														}, 100)
							 | 
						|
													})
							 | 
						|
												}
							 | 
						|
											},
							 | 
						|
											//颜色改变时刷新当前页面,否则APP-VUE可能不会立即生效
							 | 
						|
											color () {
							 | 
						|
												if ( this.$refs.flip && this.pages[this.current] ) this.$refs.flip.forceUpdate(this.current)
							 | 
						|
											},
							 | 
						|
											fontSize () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											lineHeight () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											slide () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											topGap () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											bottomGap () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											fontFamily () {
							 | 
						|
												this.$nextTick(function () {
							 | 
						|
													this.refresh()
							 | 
						|
												})
							 | 
						|
											},
							 | 
						|
											autoplay (newVal) {
							 | 
						|
												if ( this.pageType == 'scroll' ) {
							 | 
						|
													if ( !this.isLoading ) this.autoplaySync = newVal
							 | 
						|
												} else {
							 | 
						|
													this.autoplaySync = newVal
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								</script>
							 | 
						|
								
							 | 
						|
								<style scoped>
							 | 
						|
									.yingbing-reader {
							 | 
						|
										/* #ifndef APP-NVUE */
							 | 
						|
										width: 100%;
							 | 
						|
										height: 100%;
							 | 
						|
										/* #endif */
							 | 
						|
										/* #ifdef APP-NVUE */
							 | 
						|
										flex: 1;
							 | 
						|
										/* #endif */
							 | 
						|
										position: relative;
							 | 
						|
										overflow: hidden;
							 | 
						|
									}
							 | 
						|
									.yingbing-reader-content-loading {
							 | 
						|
										display: flex;
							 | 
						|
										flex-direction: column;
							 | 
						|
										align-items: center;
							 | 
						|
										justify-content: center;
							 | 
						|
									}
							 | 
						|
									.yingbing-reader-content-loading-text {
							 | 
						|
										margin-top: 10px;
							 | 
						|
										font-size: 15px;
							 | 
						|
									}
							 | 
						|
									.yingbing-reader-content-loading-tip {
							 | 
						|
										margin-top: 10px;
							 | 
						|
										font-size: 12px;
							 | 
						|
									}
							 | 
						|
									.yingbing-hidden {
							 | 
						|
										visibility: hidden;
							 | 
						|
									}
							 | 
						|
									
							 | 
						|
									/* 滚动模式样式 */
							 | 
						|
									.yingbing-scroll-reader {
							 | 
						|
										/* #ifndef APP-NVUE */
							 | 
						|
										width: 100%;
							 | 
						|
										height: 100%;
							 | 
						|
										display: flex;
							 | 
						|
										flex-direction: column;
							 | 
						|
										box-sizing: border-box;
							 | 
						|
										/* #endif */
							 | 
						|
										/* #ifdef APP-NVUE */
							 | 
						|
										flex: 1;
							 | 
						|
										/* #endif */
							 | 
						|
										position: relative;
							 | 
						|
									}
							 | 
						|
									.yingbing-scroll {
							 | 
						|
										flex: 1;
							 | 
						|
										position: relative;
							 | 
						|
									}
							 | 
						|
									
							 | 
						|
									/* 翻页模式样式 */
							 | 
						|
									.yingbing-reader-absolute {
							 | 
						|
										position: absolute;
							 | 
						|
										left: 0;
							 | 
						|
										top: 0;
							 | 
						|
										right: 0;
							 | 
						|
										bottom: 0;
							 | 
						|
									}
							 | 
						|
									.yingbing-flip-reader .loading-box {
							 | 
						|
										background-color: rgba(0,0,0,.2);
							 | 
						|
										align-items: center;
							 | 
						|
										justify-content: center;
							 | 
						|
										/* #ifdef APP-NVUE */
							 | 
						|
										flex: 1;
							 | 
						|
										/* #endif */
							 | 
						|
										/* #ifndef APP-NVUE */
							 | 
						|
										display: flex;
							 | 
						|
										flex-direction: column;
							 | 
						|
										height: 100%;
							 | 
						|
										/* #endif */
							 | 
						|
									}
							 | 
						|
									.yingbing-flip-reader .loading-text {
							 | 
						|
										color: #ffffff;
							 | 
						|
									}
							 | 
						|
									.yingbing-flip-reader-wrapper {
							 | 
						|
										/* #ifndef APP-NVUE */
							 | 
						|
										display: flex;
							 | 
						|
										flex-direction: column;
							 | 
						|
										/* #endif */
							 | 
						|
									}
							 | 
						|
									.yingbing-flip-reader-content {
							 | 
						|
										position: relative;
							 | 
						|
										flex: 1;
							 | 
						|
									}
							 | 
						|
								</style>
							 |