Files
SEONexus/code/public/template/shikong/js/novel-info.js
2025-04-21 17:49:17 +08:00

266 lines
9.8 KiB
JavaScript

class NovelReader {
/**
* 创建一个小说阅读器。
* @param {Array} chapters - 小说的章节数组。
* @param {number} pageSize - 每页的字符数。
* @param {string} chapterElementId - 显示章节内容的元素选择器。
* @param {string} prevPageButtonIdTop - 顶部上一页按钮元素的选择器。
* @param {string} nextPageButtonIdTop - 顶部下一页按钮元素的选择器。
* @param {string} prevPageButtonIdBottom - 底部上一页按钮元素的选择器。
* @param {string} nextPageButtonIdBottom - 底部下一页按钮元素的选择器。
* @param {string} switchButtonId - 自动滚动开关按钮元素的选择器。
* @param {number} scrollStep - 自动滚动每次滚动的像素值。
*/
constructor(chapters, pageSize, chapterElementId, prevPageButtonIdTop, nextPageButtonIdTop, prevPageButtonIdBottom, nextPageButtonIdBottom, switchButtonId, scrollStep = 50) {
this.chapters = chapters;
this.pageSize = pageSize;
this.currentChapterIndex = 0;
this.currentPageIndex = 0;
this.pages = [];
this.intervalId = null;
this.isScrolling = false;
this.scrollStep = scrollStep;
this.chapterElement = document.querySelector(chapterElementId);
this.prevPageButtonTop = document.querySelector(prevPageButtonIdTop);
this.nextPageButtonTop = document.querySelector(nextPageButtonIdTop);
this.prevPageButtonBottom = document.querySelector(prevPageButtonIdBottom);
this.nextPageButtonBottom = document.querySelector(nextPageButtonIdBottom);
this.switchButton = document.querySelector(switchButtonId);
this.init();
}
/**
* 初始化小说阅读器。
*/
init() {
this.pages = this.paginateChapter(this.chapters[this.currentChapterIndex]);
this.loadPage(0);
this.prevPageButtonTop.addEventListener('click', this.prevPage.bind(this));
this.nextPageButtonTop.addEventListener('click', this.nextPage.bind(this));
this.prevPageButtonBottom.addEventListener('click', this.prevPage.bind(this));
this.nextPageButtonBottom.addEventListener('click', this.nextPage.bind(this));
this.switchButton.addEventListener('click', this.toggleScrolling.bind(this));
// 检查本地存储中的自动播放设置
const autoPlay = localStorage.getItem('autoPlay');
if (autoPlay === 'true') {
this.startScrolling();
$(this.switchButton).addClass('van-switch--on').attr('aria-checked', 'true');
}
// 监听用户滚动
window.addEventListener('scroll', () => {
if (!this.isScrolling && window.scrollY === 0 && autoPlay === 'true') {
this.startScrolling();
}
});
}
/**
* 将章节分页,确保标签不会被切割。
* @param {string} chapter - 章节内容。
* @return {Array} - 切分成页的章节内容。
*/
paginateChapter(chapter) {
const pages = [];
let currentPage = '';
let currentIndex = 0;
while (currentIndex < chapter.length) {
const nextSlice = chapter.slice(currentIndex, currentIndex + this.pageSize);
const lastOpenTagIndex = nextSlice.lastIndexOf('<');
const lastCloseTagIndex = nextSlice.lastIndexOf('>');
if (lastOpenTagIndex > lastCloseTagIndex) {
const nextCloseTagIndex = chapter.indexOf('>', currentIndex + this.pageSize);
if (nextCloseTagIndex === -1) {
currentPage += chapter.slice(currentIndex);
currentIndex = chapter.length;
} else {
currentPage += chapter.slice(currentIndex, nextCloseTagIndex + 1);
currentIndex = nextCloseTagIndex + 1;
}
} else {
currentPage += nextSlice;
currentIndex += this.pageSize;
}
if (currentPage.length >= this.pageSize || currentIndex >= chapter.length) {
pages.push(currentPage);
currentPage = '';
}
}
return pages;
}
/**
* 加载指定的页面。
* @param {number} index - 要加载的页码。
*/
loadPage(index) {
if (index >= 0 && index < this.pages.length) {
this.chapterElement.innerHTML = this.pages[index];
this.currentPageIndex = index;
}
this.updateNavButtons();
// 获取元素
let element = document.querySelector('#app');
// 获取元素距离浏览器滚动到顶部的距离
let distanceToTop = element.getBoundingClientRect().top + window.scrollY;
//console.log('距离顶部的距离:', distanceToTop);
$(window).scrollTop(distanceToTop);
}
/**
* 更新导航按钮。
* @param {HTMLElement} prevButton - 上一页按钮元素。
* @param {HTMLElement} nextButton - 下一页按钮元素。
*/
updateButtonState(prevButton, nextButton) {
if (this.currentPageIndex === 0) {
prevButton.textContent = '上一章';
} else {
prevButton.textContent = '上一页';
}
prevButton.disabled = this.currentPageIndex === 0 && this.currentChapterIndex === 0;
if (this.currentPageIndex === this.pages.length - 1) {
nextButton.textContent = '下一章';
} else {
nextButton.textContent = '下一页';
}
nextButton.disabled = this.currentPageIndex === this.pages.length - 1 && this.currentChapterIndex === this.chapters.length - 1;
}
/**
* 根据当前页面和章节更新导航按钮。
*/
updateNavButtons() {
this.updateButtonState(this.prevPageButtonTop, this.nextPageButtonTop);
this.updateButtonState(this.prevPageButtonBottom, this.nextPageButtonBottom);
}
/**
* 导航到上一页或上一章。
*/
prevPage() {
if (this.currentPageIndex > 0) {
this.loadPage(this.currentPageIndex - 1);
} else if (this.currentChapterIndex > 0) {
this.currentChapterIndex -= 1;
this.pages = this.paginateChapter(this.chapters[this.currentChapterIndex]);
this.loadPage(this.pages.length - 1);
}else{
// 更新 URL
let strUpdatedUrl = this.updateChapterId(location.href,intPre);
location.href=strUpdatedUrl
}
}
/**
* 导航到下一页或下一章。
*/
nextPage() {
if (this.currentPageIndex < this.pages.length - 1) {
this.loadPage(this.currentPageIndex + 1);
} else if (this.currentChapterIndex < this.chapters.length - 1) {
this.currentChapterIndex += 1;
this.pages = this.paginateChapter(this.chapters[this.currentChapterIndex]);
this.loadPage(0);
} else {
// 更新 URL
let strUpdatedUrl = this.updateChapterId(location.href,intNext);
//console.log(strUpdatedUrl)
location.href=strUpdatedUrl
//this.stopScrolling(); // 如果没有下一页和下一章,则停止滚动
}
}
updateChapterId(url,intChapterId) {
const urlObj = new URL(url);
const params = urlObj.searchParams;
if (params.has('chapter_id')) {
// 如果存在 chapter_id 参数,则将其值改为 1
params.set('chapter_id', intChapterId);
} else {
// 如果不存在 chapter_id 参数,则追加该参数
params.append('chapter_id', intChapterId);
}
// 返回更新后的 URL
return urlObj.toString();
}
/**
* 启动自动滚动。
*/
startScrolling() {
var interval = parseInt($('.van-stepper__input').val()) * 1000; // 将秒转换为毫秒
//console.log('启动滚动,间隔:', interval);
this.isScrolling = true;
localStorage.setItem('autoPlay', 'true');
this.intervalId = setInterval(() => {
var scrollTop = $(window).scrollTop();
var scrollHeight = $(document).height();
var clientHeight = $(window).height();
//console.log('scrollTop:', scrollTop, 'scrollHeight:', scrollHeight, 'clientHeight:', clientHeight);
if (scrollTop + clientHeight >= scrollHeight) {
console.log('到达底部,触发下一页或下一章');
this.nextPage();
} else {
$(window).scrollTop(scrollTop + this.scrollStep); // 向下滚动50px
//console.log('滚动到:', scrollTop + this.scrollStep);
}
}, interval);
}
/**
* 停止自动滚动。
*/
stopScrolling() {
clearInterval(this.intervalId);
this.intervalId = null;
this.isScrolling = false;
localStorage.setItem('autoPlay', 'false');
//console.log('滚动停止');
}
/**
* 切换自动滚动状态。
*/
toggleScrolling() {
if (this.isScrolling) {
this.stopScrolling();
$(this.switchButton).removeClass('van-switch--on').attr('aria-checked', 'false');
} else {
this.startScrolling();
$(this.switchButton).addClass('van-switch--on').attr('aria-checked', 'true');
}
}
}
// 初始化小说阅读器
document.addEventListener('DOMContentLoaded', function () {
let element = document.getElementById('novel_content')
// 获取元素的文本内容
let text = element.textContent;
const chapters = [
text
];
const pageSize = 1000; // 每页的字数
new NovelReader(chapters, pageSize, '.novel-content pre', '.prevPageTop', '.nextPageTop', '.prevPageBottom', '.nextPageBottom', '.van-switch', 300);
});