<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>
|