|                                                                                                                                                                                                                                                                                                                                                                                                                                                        |  | <template>	<view class="yingbing-whole-reader"	id="yingbing-whole-reader"	:data-start="start"	:data-color="color"	:data-title="title"	:data-background="background"	:data-split="split"	:data-fontSize="fontSize"	:data-fontFamily="fontFamily"	:data-lineGap="lineGap"	:data-topGap="topGap"	:data-bottomGap="bottomGap"	:data-slide="slide"	:data-pageType="pageType"	:data-backShow="backShow"	:data-headerShow="headerShow"	:data-footerShow="footerShow"	:data-autoplay="autoplaySync"	:data-interval="interval"	:data-unableClickPage="unableClickPage"	:data-selectable="selectable"	:selectable="selectable" :change:selectable="wholeReader.selectableWatcher"	:unableClickPage="unableClickPage" :change:unableClickPage="wholeReader.unableClickPageWatcher"	:autoplay="autoplaySync" :change:autoplay="wholeReader.autoplayWatcher"	:interval="interval" :change:interval="wholeReader.intervalWatcher"	:content="contentSync" :change:content="wholeReader.contentWatcher"	:fontSize="fontSize" :change:fontSize="wholeReader.fontSizeWatcher"	:fontFamily="fontFamily" :change:fontFamily="wholeReader.fontFamilyWatcher"	:split="split" :change:split="wholeReader.splitWatcher"	:lineGap="lineGap" :change:lineGap="wholeReader.lineGapWatcher"	:topGap="topGap" :change:topGap="wholeReader.topGapWatcher"	:bottomGap="bottomGap" :change:bottomGap="wholeReader.bottomGapWatcher"	:slide="slide" :change:slide="wholeReader.slideWatcher"	:pageType="pageType" :change:pageType="wholeReader.pageTypeWatcher"	:backShow="backShow" :change:backShow="wholeReader.backShowWatcher"	:headerShow="headerShow" :change:headerShow="wholeReader.headerShowWatcher"	:footerShow="footerShow" :change:footerShow="wholeReader.footerShowWatcher"	:background="background" :change:background="wholeReader.backgroundWatcher"	:color="color" :change:color="wholeReader.colorWatcher"	:isRender="isRender" :change:isRender="wholeReader.renderWatcher"	:isRefresh="isRefresh" :change:isRefresh="wholeReader.refreshWatcher"	:pageTo="pageTo" :change:pageTo="wholeReader.pageToWatcher"	@touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">	</view></template>
<script>	import TouchClickMixin from '../mixin/touch-click.js'	export default {		options: {			addGlobalClass: true,			virtualHost: true,  //  将自定义节点设置成虚拟的,更加接近Vue组件的表现。我们不希望自定义组件的这个节点本身可以设置样式、响应 flex 布局等,而是希望自定义组件内部的第一层节点能够响应 flex 布局或者样式由自定义组件本身完全决定
		},		mixins: [TouchClickMixin],		props: {			//自动播放
			autoplay: {				type: Boolean,				default: false			},			interval: {				type: [Number, String],				default: 5000			},			//字体颜色
			color: {				type: String,				default: '#333333'			},			//字体大小(单位px)
			fontSize: {				type: [Number, String],				default: 15			},			fontFamily: {				type: String,				default: 'Arial'			},			//背景颜色
			background: {				type: String,				default: '#fcd281'			},			//分隔符
			split: {				type: String,				default: ''			},			//翻页方式
			pageType: {				type: String,				default: 'scroll'			},			//行间距(单位px)
			lineGap: {				type: [Number, String],				default: 15			},			//页面左右边距(单位px)
			slide: {				type: [Number, String],				default: 20			},			//页面上边距(单位px)
			topGap: {				type: [Number, String],				default: 10			},			//页面下边距(单位px)
			bottomGap: {				type: [Number, String],				default: 10			},			backShow: {				type: Boolean,				default: false			},			headerShow: {				type: Boolean,				default: true			},			footerShow: {				type: Boolean,				default: true			},			//是否关闭点击左右2侧位置翻页
			unableClickPage: {				type: Boolean,				default: false			},			//开启文本选择
			selectable: {				type: Boolean,				default: false			}		},		computed: {			contentSync () {				return {content: this.content}			}		},		data () {			return {				title: '',				content: '',				start: 0,				isRender: false,//是否渲染页面
				isRefresh: false,//是否刷新页面
				pageTo: 0			}		},		created() {			this.autoplaySync = this.autoplay		},		beforeDestroy() {			if ( this.touchTimer ) {//清楚定时任务
				clearTimeout(this.touchTimer)				this.touchTimer = null			}			if ( this.longTimer ) {//清楚定时任务
				clearTimeout(this.longTimer)				this.longTimer = null			}		},		methods: {			//初始化
			init ({content, title, start}) {				this.content = content				this.title = title				this.$emit('setCatalog', this.getCatalog(this.content));				this.change(start)			},			//跳转
			async change (start) {				const rect = await this.getRect()				this.windowWidth = rect.width				this.windowHeight = rect.height				this.start = parseInt(start)				this.isRender = false				this.$nextTick(function () {					this.isRender = true				})			},			//刷新
			async refresh () {				const rect = await this.getRect()				this.windowWidth = rect.width				this.windowHeight = rect.height				this.isRefresh = false				this.$nextTick(function () {					this.isRefresh = true				})			},			prev () {				this.pageTo = 0				this.$nextTick(function(){					this.pageTo = -1				})			},			next () {				this.pageTo = 0				this.$nextTick(function(){					this.pageTo = 1				})			},			//抛出阅读页面改变事件
			handleChange (e) {				this.$emit('change', e)			},			//往后翻页完成事件
			handleEnded () {				this.$emit('ended')			},			//往前翻页完成事件
			handleStarted () {				this.$emit('started')			},			handleBack () {				this.$emit('back')			},			//使用正则获取章节目录 并抛出事件
			getCatalog (content) {				// const reg = new RegExp(/(第?[一二两三四五六七八九十○零百千万亿0-91234567890※✩★☆]{1,6}[章回卷节折篇幕集部]?[、.-\s][^\n]*)[_,-]?/g);
				const reg = new RegExp(/(第+[一二两三四五六七八九十○零百千万亿0-91234567890※✩★☆]{1,6}[章回卷节折篇幕集部]?[、.-\s::,,][^\n]*)[_,-]?/g)				let match = '';				let catalog = [];				let chapter = 0				while ((match = reg.exec(content)) != null) {					chapter++					catalog.push({						title: match[0],						start: match.index					})				}				return catalog.length > 0 ? catalog : [{					start: 0,					title: this.title || '整章'				}]			},			getRect () {				return new Promise(resolve => {					uni.createSelectorQuery().in(this).select('.yingbing-whole-reader').boundingClientRect(data => {						resolve(data)					}).exec();				})			}		},		watch: {			autoplay (newVal) {				this.autoplaySync = newVal			}		}	}</script><!-- #ifdef H5 || APP-VUE --><script lang="renderjs" module="wholeReader" type="module">	import Wholereader from "./wholereader.js"	export default {		data () {			return {				content: '',				whole: null			}		},		methods: {			renderWatcher (newVal) {				if ( newVal && this.content ) {					if ( this.whole ) this.whole.destroy()					this.whole = new Wholereader({						container: document.querySelector('#yingbing-whole-reader'),						autoplay: this.getData('autoplay') == 'true' ? true : false,						interval: this.getData('interval'),						content: this.getData('content'),						title: this.getData('title'),						color: this.getData('color'),						background: this.getData('background'),						fontSize: this.getData('fontSize'),						fontFamily: this.getData('fontFamily'),						slide: this.getData('slide'),						topGap: this.getData('topGap'),						bottomGap: this.getData('bottomGap'),						lineGap: this.getData('lineGap'),						split: this.getData('split'),						headerShow: this.getData('headerShow') == 'true' ? true : false,						footerShow: this.getData('footerShow') == 'true' ? true : false,						backShow: this.getData('backShow') == 'true' ? true : false,						pageType: this.getData('pageType'),						unableClickPage: this.getData('unableClickPage') == 'true' ? true : false,						selectable: this.getData('selectable') == 'true' ? true : false					})					this.whole.render(this.getData('start'))//开始渲染页面
					this.whole.on('change', e => {//注册翻页改变事件
						this.triggerMethod('handleChange', e)					})					this.whole.on('ended', () => {//注册往后翻页完成事件
						this.triggerMethod('handleEnded')					})					this.whole.on('started', () => {//注册往前翻页完成事件
						this.triggerMethod('handleStarted')					})					this.whole.on('back', () => {//点击返回按钮事件
						this.triggerMethod('handleBack')					})				}			},			refreshWatcher (newVal) {				if ( this.refreshTimer ) {					window.clearTimeout(this.refreshTimer)					this.refreshTimer = null				}				if ( newVal && this.whole ) {					this.refreshTimer = window.setTimeout(() => {						 this.whole.refresh()					}, 200)				}			},			pageToWatcher (newVal) {				if ( newVal == -1 ) this.whole && this.whole.prev()				if ( newVal == 1 ) this.whole && this.whole.next()			},			autoplayWatcher (newVal) {				this.whole && this.whole.setConfig('autoplay', newVal)			},			intervalWatcher (newVal) {				this.whole && this.whole.setConfig('interval', newVal)			},			contentWatcher (newVal, oldVal) {				this.content = newVal.content			},			fontSizeWatcher (newVal) {				this.whole && this.whole.setConfig('fontSize', newVal)				this.refreshWatcher(true)			},			fontFamilyWatcher (newVal) {				this.whole && this.whole.setConfig('fontFamily', newVal)				this.refreshWatcher(true)			},			splitWatcher (newVal) {				this.whole && this.whole.setConfig('split', newVal)				this.refreshWatcher(true)			},			lineGapWatcher (newVal) {				this.whole && this.whole.setConfig('lineGap', newVal)				this.refreshWatcher(true)			},			topGapWatcher (newVal) {				this.whole && this.whole.setConfig('topGap', newVal)				this.refreshWatcher(true)			},			bottomGapWatcher (newVal) {				this.whole && this.whole.setConfig('bottomGap', newVal)				this.refreshWatcher(true)			},			slideWatcher (newVal) {				this.whole && this.whole.setConfig('slide', newVal)				this.refreshWatcher(true)			},			pageTypeWatcher (newVal) {				this.whole && this.whole.setConfig('pageType', newVal)				this.refreshWatcher(true)			},			backShowWatcher (newVal) {				this.whole && this.whole.setConfig('backShow', newVal)				this.refreshWatcher(true)			},			headerShowWatcher (newVal) {				this.whole && this.whole.setConfig('headerShow', newVal)				this.refreshWatcher(true)			},			footerShowWatcher (newVal) {				this.whole && this.whole.setConfig('footerShow', newVal)				this.refreshWatcher(true)			},			backgroundWatcher (newVal) {				this.whole && this.whole.setConfig('background', newVal)				this.refreshWatcher(true)			},			colorWatcher (newVal) {				this.whole && this.whole.setConfig('color', newVal)				this.refreshWatcher(true)			},			selectableWatcher (newVal) {				this.whole && this.whole.setConfig('selectable', newVal)				this.refreshWatcher(true)			},			unableClickPageWatcher (newVal) {				this.whole && this.whole.setConfig('unableClickPage', newVal)			},			getData (name) {				const dom = document.getElementById('yingbing-whole-reader')				if ( name == 'content' ) {					return this.content.replace(/\t/g, ' ').replace(/ /g, ' ')				} else if ( ['fontSize', 'lineGap', 'topGap', 'bottomGap', 'slide', 'start', 'interval'].includes(name) ) {					return parseInt(dom.getAttribute('data-' + name))				} else {					return dom.getAttribute('data-' + name)				}			},			triggerMethod (name, args) {				// #ifndef H5
				// UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
				//   cid: this._$id,
				//   method: name,
				//   args: args
				// })
				this.$ownerInstance.callMethod(name, args)				// #endif
				// #ifdef H5
				this[name](args)				// #endif
			}		}	}</script><!-- #endif -->
<style scoped>	@import url(/uni_modules/yingbing-ReadPage/components/yingbing-whole-reader/wholereader.css);	.yingbing-whole-reader {		width: 100%;		height: 100%;		box-sizing: border-box;		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;	}</style>
 |