451 lines
15 KiB
JavaScript
451 lines
15 KiB
JavaScript
import Util from '../../../js_sdk/util.js'
|
||
export default {
|
||
props: {
|
||
measureSize: {
|
||
type: Object,
|
||
default () {
|
||
return new Object
|
||
}
|
||
}
|
||
},
|
||
data () {
|
||
return {
|
||
computedResolve: null,
|
||
chineseSize: 0,
|
||
spaceSize: 0,
|
||
lowerSize: 0,
|
||
upperSize: 0,
|
||
numberSize: 0,
|
||
specialSize: 0
|
||
}
|
||
},
|
||
methods: {
|
||
reset (data, pages = []) {
|
||
if ( data.custom && data.custom.length > 0 ) {
|
||
pages.length > 0 ? pages[pages.length - 1].isLastPage = false : null
|
||
data.custom.forEach(custom => {
|
||
let type = ''
|
||
if ( custom.indexOf('slot:') > -1 ) {
|
||
type = 'slot'
|
||
custom = custom.split(':')[1]
|
||
} else {
|
||
type = 'custom'
|
||
let clicks = custom.match(/onclick=\"*([\s\S]*?)\"/ig);
|
||
if ( clicks ) {
|
||
clicks.forEach(click => {
|
||
let name = click.match(/onclick=\"*([\s\S]*?)(\(|\")/)[1]
|
||
let func = click.match(/onclick=\"*([\s\S]*?)\"/)
|
||
let args = func[1].replace(name, '')
|
||
args = args ? args.slice(1, args.length - 1).replace(/\s/g, '') : ''
|
||
custom = custom.replace(func[0], `onclick="triggerCustomClick('${name}', [${args}])"`)
|
||
})
|
||
}
|
||
|
||
}
|
||
let end = pages.length > 0 ? pages[pages.length - 1].end : 0
|
||
pages.push({
|
||
chapter: data.chapter,
|
||
title: data.title || '',
|
||
type: type,
|
||
dataId: data.chapter * 100000 + end,
|
||
start: end,
|
||
end: end + 10,
|
||
isLastPage: false,
|
||
text: custom
|
||
})
|
||
})
|
||
pages[pages.length - 1].isLastPage = true
|
||
}
|
||
this.computedResolve(pages)
|
||
this.computedResolve = null
|
||
},
|
||
measureText (text, fontSize=10) {
|
||
text = new String(text);
|
||
text = text.split('');
|
||
let width = 0;
|
||
text.forEach((item) => {
|
||
if (/[a-z]/.test(item)) {
|
||
width += this.measureSize.lower || this.lowerSize || 7
|
||
} else if ( /[A-Z]/.test(item) ) {
|
||
width += this.measureSize.upper || this.upperSize || 7
|
||
} else if (/[0-9]/.test(item)) {
|
||
width += this.measureSize.number || this.numberSize || 5.5
|
||
} else if (/[\u4e00-\u9fa5]/.test(item)) { //中文匹配
|
||
width += this.measureSize.chinese || this.chineseSize || 10
|
||
} else if (/\s/.test(item)) {
|
||
width += this.measureSize.space || this.spaceSize || 3.5
|
||
} else if (/[`!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/.test(item)) {
|
||
width += this.measureSize.special || this.specialSize || 8
|
||
} else {
|
||
width += this.measureSize.other || this.chineseSize || 10
|
||
}
|
||
});
|
||
return width * fontSize / 10;
|
||
},
|
||
getComputedTextSize (selector, el) {
|
||
let arr = []
|
||
arr.push(Util.getRect('.computed-text-chinese', this.$refs.computedTextChinese, this))
|
||
arr.push(Util.getRect('.computed-text-space', this.$refs.computedTextSpace, this))
|
||
arr.push(Util.getRect('.computed-text-lower', this.$refs.computedTextLower, this))
|
||
arr.push(Util.getRect('.computed-text-upper', this.$refs.computedTextUpper, this))
|
||
arr.push(Util.getRect('.computed-text-number', this.$refs.computedTextNumber, this))
|
||
arr.push(Util.getRect('.computed-text-special', this.$refs.computedTextSpecial, this))
|
||
Promise.all(arr).then(ress => {
|
||
ress.forEach((res, key) => {
|
||
if ( key == 0 ) {
|
||
this.chineseSize = res.width * (10 / 20)
|
||
}
|
||
if ( key == 1 ) {
|
||
this.spaceSize = res.width * (10 / 20)
|
||
}
|
||
if ( key == 2 ) {
|
||
this.lowerSize = res.width * (10 / 20)
|
||
}
|
||
if ( key == 3 ) {
|
||
this.upperSize = res.width * (10 / 20)
|
||
}
|
||
if ( key == 4 ) {
|
||
this.numberSize = res.width * (10 / 20)
|
||
}
|
||
if ( key == 5 ) {
|
||
this.specialSize = res.width * (10 / 20)
|
||
}
|
||
// console.log('chineseSize', this.chineseSize);
|
||
// console.log('spaceSize', this.spaceSize);
|
||
// console.log('lowerSize', this.lowerSize);
|
||
// console.log('upperSize', this.upperSize);
|
||
// console.log('numberSize', this.numberSize);
|
||
// console.log('specialSize', this.specialSize);
|
||
})
|
||
})
|
||
},
|
||
async computedText (data, start) {
|
||
let rect = await this.getRect()
|
||
let viewWidth = rect.width - (this.options.slide * 2)
|
||
let viewHeight = rect.height - this.options.topGap - this.options.bottomGap
|
||
if ( this.options.headerShow ) viewHeight = viewHeight - uni.upx2px(50)
|
||
if ( this.options.footerShow ) viewHeight = viewHeight - uni.upx2px(50)
|
||
let pageHeight = this.options.fontSize + this.options.lineHeight;
|
||
let strs = [];
|
||
let page = {
|
||
title: data.title || '',
|
||
chapter: data.chapter,
|
||
type: 'text',
|
||
dataId: data.chapter * 100000 + start,
|
||
start: start,
|
||
end: 0,
|
||
isLastPage: false,
|
||
text: []
|
||
}
|
||
let length = 0;
|
||
let contentSync = data.content.substr(start).replace(/\t/g, ' ').replace(/ /g, ' ');
|
||
let lastIndex = 0;
|
||
while ( (pageHeight + this.options.fontSize + this.options.lineHeight) <= viewHeight ) {
|
||
strs.push('');
|
||
let lineWidth = 0;
|
||
let charText = ''
|
||
for ( let i = lastIndex; i < contentSync.length; i++ ) {
|
||
const char = contentSync.charAt(i)
|
||
if ( JSON.stringify(char) == JSON.stringify('\r') || JSON.stringify(char) == JSON.stringify('\n') ) {
|
||
lineWidth += this.measureText(charText, this.options.fontSize);
|
||
if ( lineWidth >= viewWidth ) {
|
||
lastIndex = i - charText.length+ 1;
|
||
break;
|
||
}
|
||
strs[strs.length - 1] += charText
|
||
length += charText.length + 1
|
||
page.end = page.start + length;
|
||
lastIndex = i + 1;
|
||
break;
|
||
}
|
||
charText += char
|
||
if ( !this.split || char == this.split ) {
|
||
lineWidth += this.measureText(charText, this.options.fontSize);
|
||
if ( lineWidth >= viewWidth ) {
|
||
lastIndex = i - charText.length+ 1;
|
||
break;
|
||
}
|
||
strs[strs.length - 1] += charText
|
||
length += charText.length
|
||
page.end = page.start + length
|
||
charText = ''
|
||
}
|
||
}
|
||
pageHeight += this.options.fontSize + this.options.lineHeight;
|
||
if ( page.end >= data.content.length - 1 ) {
|
||
page.isLastPage = true;
|
||
break;
|
||
}
|
||
}
|
||
page.text = strs;
|
||
return page;
|
||
},
|
||
getRect () {
|
||
return new Promise (resolve => {
|
||
// #ifndef APP-NVUE
|
||
const query = uni.createSelectorQuery().in(this);
|
||
query.select('.yingbing-read-page').boundingClientRect(data => {
|
||
resolve(data)
|
||
}).exec();
|
||
// #endif
|
||
// #ifdef APP-NVUE
|
||
uni.requireNativePlugin('dom').getComponentRect(this.$refs.yingbingReadPage, res => {
|
||
resolve(res.size)
|
||
})
|
||
// #endif
|
||
})
|
||
},
|
||
getPages (data) {
|
||
let pages = [];
|
||
const doWhile = (start = 0) => {
|
||
this.computedText(data, start).then(page => {
|
||
pages.push(page);
|
||
if ( page.isLastPage ) {
|
||
this.reset(data, pages)
|
||
} else {
|
||
doWhile(page.end);
|
||
}
|
||
});
|
||
}
|
||
doWhile();
|
||
},
|
||
computedChapter(data) {
|
||
return new Promise(resolve => {
|
||
this.computedResolve = resolve
|
||
data.content ? this.getPages(data) : this.reset(data)
|
||
})
|
||
},
|
||
//绘制页面
|
||
resetPage(data) {
|
||
setTimeout(() => {
|
||
//一次最多渲染3章的内容,根据定位的章节剪切出3章内容渲染
|
||
let currentChapter = data.currentChapter || this.contents[0].chapter
|
||
let nowIndex = this.contents.findIndex(item => item.chapter == currentChapter);
|
||
let prevIndex = -1;
|
||
let nextIndex = -1;
|
||
let contents = [];
|
||
if (!this.contents[nowIndex].isStart) prevIndex = this.contents.findIndex(item => item.chapter == currentChapter - 1);
|
||
if (!this.contents[nowIndex].isEnd) nextIndex = this.contents.findIndex(item => item.chapter == currentChapter + 1);
|
||
if (prevIndex > -1) {
|
||
contents.push(this.contents[prevIndex])
|
||
}
|
||
contents.push(this.contents[nowIndex])
|
||
if (nextIndex > -1) {
|
||
contents.push(this.contents[nextIndex])
|
||
}
|
||
let arr = [];
|
||
const dowhile = (i) => {
|
||
let item = contents[i];
|
||
this.computedChapter(item).then(pages => {
|
||
if (currentChapter == item.chapter) {
|
||
let index = Object.keys(pages).findIndex(key => data.start >= pages[key].start && data.start < pages[key].end)
|
||
this.currentDataId = pages[index > -1 ? index : 0].dataId;
|
||
}
|
||
arr = arr.concat(pages)
|
||
if (i == contents.length - 1) {
|
||
if ( this.options.pageType != 'scroll' ) {
|
||
if ( !this.firstTipUnable ) {
|
||
arr.unshift({
|
||
title: contents[0].title || '',
|
||
chapter: contents[0].chapter,
|
||
type: contents[0].isStart ? 'top' : 'loading',
|
||
direction: 'prev',
|
||
dataId: arr[0].dataId - 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
} else if ( !contents[0].isStart ) {
|
||
arr.unshift({
|
||
title: contents[0].title || '',
|
||
chapter: contents[0].chapter,
|
||
type: 'loading',
|
||
direction: 'prev',
|
||
dataId: arr[0].dataId - 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
}
|
||
if ( !this.lastTipUnable ) {
|
||
arr.push({
|
||
title: item.title || '',
|
||
chapter: item.chapter,
|
||
type: item.isEnd ? 'bottom' : 'loading',
|
||
direction: 'next',
|
||
dataId: arr[arr.length - 1].dataId + 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
} else if ( !contents[0].isEnd ) {
|
||
arr.push({
|
||
title: item.title || '',
|
||
chapter: item.chapter,
|
||
type: 'loading',
|
||
direction: 'next',
|
||
dataId: arr[arr.length - 1].dataId + 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
}
|
||
}
|
||
this.pages = arr
|
||
if ( this.options.pageType == 'scroll' ) {
|
||
this.$refs.list.scrollTo(0)
|
||
}
|
||
this.$nextTick(() => {
|
||
if ( this.options.pageType != 'scroll' ) {
|
||
this.$refs.flip.refresh()
|
||
this.handleFlipChange(this.currentDataId);
|
||
} else {
|
||
setTimeout(() => {
|
||
Util.getRect('#scroll-item_' + this.currentDataId, Util.getRefs(this, 'scrollItem_' + this.currentDataId, 0), this).then(rect => {
|
||
this.$refs.list.scrollTo(rect.top)
|
||
})
|
||
}, 50)
|
||
}
|
||
this.initLoading = false;
|
||
this.preload(currentChapter);
|
||
})
|
||
} else {
|
||
setTimeout(() => {
|
||
dowhile(i + 1)
|
||
}, 100)
|
||
}
|
||
})
|
||
}
|
||
dowhile(0)
|
||
}, 50)
|
||
},
|
||
computedPage(e) {
|
||
this.computedChapter(e.content).then((pages) => {
|
||
let arr = [];
|
||
const pagesSync = e.type == 'prev' ? pages.concat(this.pages) : this.pages.concat(pages);
|
||
let newPages = pagesSync.filter(item => (item.type == 'text' || item.type == 'custom' || item.type == 'slot'))
|
||
// pagesSync.forEach(item => {
|
||
// if (arr.indexOf(item.chapter) == -1) arr.push(item.chapter)
|
||
// })
|
||
// if (arr.length > 3) {
|
||
// let reChapter = e.type == 'prev' ? pagesSync[pagesSync.length - 1].chapter : pagesSync[0].chapter;
|
||
// newPages = pagesSync.filter(item => item.chapter != reChapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot'));
|
||
// } else {
|
||
// newPages = pagesSync.filter(item => (item.type == 'text' || item.type == 'custom' || item.type == 'slot'));
|
||
// }
|
||
if ( this.options.pageType != 'scroll' ) {
|
||
const prevIndex = this.contents.findIndex(content => content.chapter == newPages[0].chapter);
|
||
const nextIndex = this.contents.findIndex(content => content.chapter == newPages[newPages.length - 1].chapter);
|
||
if ( !this.firstTipUnable && this.contents[prevIndex].isStart ) {
|
||
newPages.unshift({
|
||
title: this.contents[prevIndex].title || '',
|
||
chapter: this.contents[prevIndex].chapter,
|
||
type: 'top',
|
||
direction: 'prev',
|
||
dataId: newPages[0].dataId - 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
} else {
|
||
newPages.unshift({
|
||
title: this.contents[prevIndex].title || '',
|
||
chapter: this.contents[prevIndex].chapter,
|
||
type: 'loading',
|
||
direction: 'prev',
|
||
dataId: newPages[0].dataId - 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
}
|
||
if ( !this.lastTipUnable && this.contents[nextIndex].isEnd ) {
|
||
newPages.push({
|
||
title: this.contents[nextIndex].title || '',
|
||
chapter: this.contents[nextIndex].chapter,
|
||
type: 'bottom',
|
||
direction: 'next',
|
||
dataId: newPages[newPages.length - 1].dataId + 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
} else {
|
||
newPages.push({
|
||
title: this.contents[nextIndex].title || '',
|
||
chapter: this.contents[nextIndex].chapter,
|
||
type: 'loading',
|
||
direction: 'next',
|
||
dataId: newPages[newPages.length - 1].dataId + 1,
|
||
start: 0,
|
||
end: 0
|
||
})
|
||
}
|
||
this.pages = newPages
|
||
const nowIndex = newPages.findIndex(page => page.dataId == this.currentDataId);
|
||
if ( nowIndex == -1 ) {
|
||
this.currentDataId = e.type == 'next' ? pages[0].dataId : pages[pages.length - 1].dataId;
|
||
this.handleFlipChange(this.currentDataId)
|
||
} else {
|
||
this.startAutoplay()
|
||
}
|
||
} else {
|
||
let dataId = e.type == 'prev' ? this.pages[0].dataId : this.pages[this.pages.length-1].dataId
|
||
Util.getRect('.scroll-item-wrapper', this.$refs.scrollItemWrapper, this).then(rect => {
|
||
let lastHeight = rect.height
|
||
this.pages = e.type == 'prev' ? pages.concat(this.pages) : this.pages.concat(pages)
|
||
if ( e.type == 'prev' ) {
|
||
this.$nextTick(function () {
|
||
setTimeout(() => {
|
||
Util.getRect('.scroll-item-wrapper', this.$refs.scrollItemWrapper, this).then(rect => {
|
||
this.$refs.list.scrollTo(rect.height - lastHeight)
|
||
})
|
||
}, 50)
|
||
})
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
//预加载章节
|
||
preload (chapter) {
|
||
if ( !this.enablePreload ) return false
|
||
const nowIndex = this.contents.findIndex(item => item.chapter == chapter);
|
||
let prevIndex = -2;
|
||
let nextIndex = -2;
|
||
let chapters = [];
|
||
if ( !this.contents[nowIndex].isStart ) prevIndex = this.contents.findIndex(item => item.chapter == chapter - 1);
|
||
if ( !this.contents[nowIndex].isEnd ) nextIndex = this.contents.findIndex(item => item.chapter == chapter + 1);
|
||
if ( prevIndex == -1 ) {
|
||
chapters.push(chapter - 1);
|
||
}
|
||
if ( nextIndex == -1 ) {
|
||
chapters.push(chapter + 1);
|
||
}
|
||
if ( chapters.length > 0 ) {
|
||
this.$emit('preload', chapters, (status, contents) => {
|
||
if (status == 'success') {
|
||
contents.forEach(item => {
|
||
const index = this.contents.findIndex(content => content.chapter == item.chapter)
|
||
if (index > -1) {
|
||
this.contents[index] = item;
|
||
} else {
|
||
this.contents.push(item);
|
||
}
|
||
})
|
||
}
|
||
})
|
||
}
|
||
},
|
||
filterPage (pageInfo) {
|
||
if ( pageInfo && pageInfo.dataId > -1 ) {
|
||
const nowChapters = this.pages.filter(item => item.chapter == pageInfo.chapter && (item.type == 'text' || item.type == 'custom' || item.type == 'slot'))
|
||
const currentPage = nowChapters.findIndex(item => item.dataId == pageInfo.dataId)
|
||
if ( currentPage > -1 ) {
|
||
return (currentPage + 1) + ' / ' + nowChapters.length
|
||
} else {
|
||
return pageInfo.type == 'top' ? '最前面' : pageInfo.type == 'bottom' ? '最后面' : pageInfo.type.indexOf('Loading') > -1 ? '请等待' : ''
|
||
}
|
||
} else {
|
||
return '加载中'
|
||
}
|
||
},
|
||
filterDate () {
|
||
let date = new Date()
|
||
return Util.zeroize(date.getHours()) + ':' + Util.zeroize(date.getMinutes())
|
||
}
|
||
}
|
||
} |