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); });