| | |
| | | <template> |
| | | <div class="page-main" @scroll="throttledScrollHandler"> |
| | | <div id="searchDomBox" style="display: none"> |
| | | <div id="searchContent"></div> |
| | | </div> |
| | | <div |
| | | class="public-lifeCare" |
| | | class="public-bookInnerContent" |
| | | @mouseup="handleMouseUp" |
| | | :style="{ |
| | | fontSize: fontSize ? fontSize + 'px' : '16px', |
| | |
| | | <front001 |
| | | v-if="showCatalogList.indexOf(1) > -1" |
| | | :showPageList="loadPageList" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <ChapterOne |
| | | v-if="showCatalogList.indexOf(2) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <ChapterTwo |
| | | v-if="showCatalogList.indexOf(3) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <ChapterThree |
| | | v-if="showCatalogList.indexOf(4) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <ChapterFour |
| | | v-if="showCatalogList.indexOf(5) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <ChapterFive |
| | | v-if="showCatalogList.indexOf(6) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | @Upload_initViewer="changeDomViewer" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <chapterSix |
| | | v-if="showCatalogList.indexOf(7) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <chapterSeven |
| | | v-if="showCatalogList.indexOf(8) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | @eventSwdt="swdtChange" |
| | | @Upload_initViewer="changeDomViewer" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <chapterEight |
| | | v-if="showCatalogList.indexOf(9) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <chapterNine |
| | | v-if="showCatalogList.indexOf(10) > -1" |
| | | :showPageList="loadPageList" |
| | | :questionData="questionData" |
| | | :isSearch="isSearch" |
| | | /> |
| | | <chapter010 |
| | | v-if="showCatalogList.indexOf(11) > -1" |
| | |
| | | observer: null, |
| | | loadPageObserver: null, |
| | | loadPageList: [], |
| | | questionData: {}, |
| | | questionDataMap: {}, |
| | | renderSignMap: {}, |
| | | highlightData: null, |
| | | isSearch: false, |
| | | }; |
| | | }, |
| | | computed: { |
| | |
| | | }, |
| | | }, |
| | | mounted() { |
| | | // 默认加载章节 |
| | | this.showCatalogList = [1]; |
| | | // 默认加载章节 |
| | | this.showCatalogList = [1]; |
| | | // 滚动监听节流 |
| | | this.throttledScrollHandler = _.throttle( |
| | | this.scrollFun, |
| | |
| | | }, |
| | | // 渲染笔记、高亮、划线 |
| | | renderSign: (type, data) => { |
| | | this.renderSign(type, data); |
| | | // 因为调整为页面懒加载,所以渲染标记也需要按照页面进行处理,先储存数据,页面加载完成再渲染对应的标记; |
| | | this.handelSignData(type, data); |
| | | // this.renderSign(type, data); |
| | | }, |
| | | // 删除笔记、高亮、划线 |
| | | delSign: (data) => { |
| | | this.delSign(data); |
| | | }, |
| | | // 全文检索 |
| | | searchBookByKeyword: (keyword) => { |
| | | return this.searchTextByPage(keyword); |
| | | }, |
| | | // 跳转检索结果位置 |
| | | jumpSearchItem: (data) => { |
| | | this.searchItemLocation(data); |
| | | }, |
| | | }); |
| | | } |
| | |
| | | // }, 1000); |
| | | }, |
| | | methods: { |
| | | changeDomViewer() { |
| | | setTimeout(() => { |
| | | this.initViewer(); |
| | | }, 500); |
| | | }, |
| | | // 滚动监听 |
| | | scrollFun(event) { |
| | | // 判断向上滚动还是向下滚动 |
| | |
| | | } |
| | | } |
| | | }, |
| | | |
| | | initObservation() { |
| | | const sections = ( |
| | | this.container ? this.container : document |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | initThemeColor() { |
| | | // 获取各种需要主题色的节点 |
| | | const colorDom = ( |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | getParentWithClass(element, className) { |
| | | while (element.parentElement) { |
| | | element = element.parentElement; |
| | |
| | | } |
| | | } |
| | | }, |
| | | |
| | | pageChangeCallback(entries, observer) { |
| | | //entries:代表观察到的目标元素的集合。 observer:代表观察者对象。 |
| | | entries.forEach((entry) => { |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | loadPageCallback(entries, observer) { |
| | | entries.forEach(async (entry) => { |
| | | if (entry.isIntersecting) { |
| | |
| | | "chapter" |
| | | ); |
| | | const catalog = catalogDom.getAttribute("num"); |
| | | if (!this.questionData[page]) { |
| | | if (!this.questionDataMap[page]) { |
| | | if (testData && testData[catalog]) { |
| | | if (testData[catalog][page]) { |
| | | if (Array.isArray(testData[catalog][page])) { |
| | | this.questionData[page] = await getQuestionList( |
| | | this.questionDataMap[page] = await getQuestionList( |
| | | page, |
| | | testData[catalog][page], |
| | | this.config.activeBook |
| | |
| | | this.config.activeBook |
| | | ); |
| | | } |
| | | this.questionData[page] = obj; |
| | | this.questionDataMap[page] = obj; |
| | | } |
| | | // console.log("题目", this.questionDataMap); |
| | | } |
| | | } |
| | | } |
| | |
| | | }); |
| | | } |
| | | } |
| | | // 处理高亮 |
| | | if (this.highlightData) { |
| | | // 高亮行 |
| | | setTimeout(() => { |
| | | // 获取页面所有text节点 |
| | | const pageTextList = document.createTreeWalker(target, NodeFilter.SHOW_TEXT); |
| | | // 匹配关键字 |
| | | const allPageTextNodes = []; |
| | | let currentNode = pageTextList.nextNode(); |
| | | while (currentNode) { |
| | | allPageTextNodes.push(currentNode); |
| | | currentNode = pageTextList.nextNode(); |
| | | } |
| | | for (let i = 0; i < allPageTextNodes.length; i++) { |
| | | const textDom = allPageTextNodes[i]; |
| | | let txtIndex = textDom.textContent.indexOf( |
| | | this.highlightData.txt |
| | | ); |
| | | if (txtIndex > -1) { |
| | | textDom.parentNode.style.transition = |
| | | "background-color 0.8s"; |
| | | textDom.parentNode.scrollIntoView(); |
| | | textDom.parentNode.style.backgroundColor = "#79bbf0"; |
| | | setTimeout(() => { |
| | | textDom.parentNode.style.backgroundColor = ""; |
| | | }, 1000); |
| | | } |
| | | } |
| | | }, 100); |
| | | } |
| | | if (this.loadPageList.length > 5) { |
| | | // 超过5页 |
| | | this.loadPageList.shift(); |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | initSwiper() { |
| | | const doms = ( |
| | | this.container ? this.container : document |
| | |
| | | for (let i = 0; i < pptDoms.length; i++) { |
| | | const dom = pptDoms[i]; |
| | | new Swiper(dom, { |
| | | loop: false, // 无缝 |
| | | autoplay: false, |
| | | paginationClickable: true, |
| | | slidesPerView: 1, // 一组三个 |
| | | spaceBetween: 30, // 间隔 |
| | | // 如果需要前进后退按钮 |
| | | navigation: { |
| | | nextEl: (this.container ? this.container : document).querySelector( |
| | | ".swiper-button-next" |
| | | ), |
| | | prevEl: (this.container ? this.container : document).querySelector( |
| | | ".swiper-button-prev" |
| | | ), |
| | | }, |
| | | // 窗口变化,重新init,针对F11全屏和放大缩小,必须加 |
| | | observer: true, |
| | | observeParents: true, |
| | | on: { |
| | | init:(value) => { |
| | | let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数) |
| | | let totalPages = value.slides.length; // 获取总页数 |
| | | var paginationInfoEl = dom.querySelector('.pageBox'); |
| | | if(paginationInfoEl) |
| | | paginationInfoEl.textContent = currentPage + '/' + totalPages; |
| | | loop: false, // 无缝 |
| | | autoplay: false, |
| | | paginationClickable: true, |
| | | slidesPerView: 1, // 一组三个 |
| | | spaceBetween: 30, // 间隔 |
| | | // 如果需要前进后退按钮 |
| | | navigation: { |
| | | nextEl: (this.container ? this.container : document).querySelector( |
| | | ".swiper-button-next" |
| | | ), |
| | | prevEl: (this.container ? this.container : document).querySelector( |
| | | ".swiper-button-prev" |
| | | ), |
| | | }, |
| | | slideChange:(value) => { |
| | | let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数) |
| | | let totalPages = value.slides.length; // 获取总页数 |
| | | var paginationInfoEl = dom.querySelector('.pageBox'); |
| | | if(paginationInfoEl) |
| | | paginationInfoEl.textContent = currentPage + '/' + totalPages; |
| | | // 窗口变化,重新init,针对F11全屏和放大缩小,必须加 |
| | | observer: true, |
| | | observeParents: true, |
| | | on: { |
| | | init: (value) => { |
| | | let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数) |
| | | let totalPages = value.slides.length; // 获取总页数 |
| | | var paginationInfoEl = dom.querySelector(".pageBox"); |
| | | if (paginationInfoEl) |
| | | paginationInfoEl.textContent = currentPage + "/" + totalPages; |
| | | }, |
| | | slideChange: (value) => { |
| | | let currentPage = value.activeIndex + 1; // 获取当前页(从1开始计数) |
| | | let totalPages = value.slides.length; // 获取总页数 |
| | | var paginationInfoEl = dom.querySelector(".pageBox"); |
| | | if (paginationInfoEl) |
| | | paginationInfoEl.textContent = currentPage + "/" + totalPages; |
| | | }, |
| | | }, |
| | | }, |
| | | }); |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | initViewer() { |
| | | const doms = ( |
| | | this.container ? this.container : document |
| | |
| | | for (let i = 0; i < doms.length; i++) { |
| | | const dom = doms[i]; |
| | | new Viewer(dom, { |
| | | container: this.container |
| | | ? this.container.querySelector("#app") |
| | | : "body", |
| | | navbar: true, // 显示导航栏 |
| | | toolbar: true, // 显示工具栏 |
| | | title: true, // 显示标题 |
| | | }); |
| | | } |
| | | }, |
| | | // eslint-disable-next-line |
| | | getParentWithClass(element, className) { |
| | | while (element.parentElement) { |
| | | element = element.parentElement; |
| | | if (element.classList.contains(className)) { |
| | | return element; |
| | | } |
| | | } |
| | | }, |
| | | |
| | | handleMouseUp(e) { |
| | | const selection = ( |
| | | this.container ? this.container : window |
| | |
| | | } |
| | | } |
| | | }, |
| | | |
| | | swdtChange(data) { |
| | | if (this.$store.state.qiankun && this.$store.state.qiankun.chooseWords) { |
| | | this.$store.state.qiankun.chooseWords({ |
| | |
| | | }); |
| | | } |
| | | }, |
| | | |
| | | // 根据关键字全文检索 |
| | | searchTextByPage(keyword) { |
| | | const searchResult = []; |
| | | let catalogIndex = 0; |
| | | // 所有章节组件(每本书制作时单独配置) |
| | | const pageData = { |
| | | front001, |
| | | ChapterOne, |
| | | ChapterTwo, |
| | | ChapterThree, |
| | | ChapterFour, |
| | | ChapterFive, |
| | | chapterSix, |
| | | chapterSeven, |
| | | chapterEight, |
| | | chapterNine, |
| | | chapter010, |
| | | chapter011, |
| | | chapter012, |
| | | chapter013, |
| | | chapter014, |
| | | chapter015, |
| | | chapter016, |
| | | chapter017, |
| | | chapter018, |
| | | }; |
| | | // 遍历所有章节文件 |
| | | for (const key in pageData) { |
| | | catalogIndex++; |
| | | let pageComponent, pageExample; |
| | | // 先渲染一次当前章节文件(这时页面的内容为空),获取页码信息 |
| | | pageComponent = Vue.extend(pageData[key]); |
| | | pageExample = new pageComponent({ |
| | | propsData: { |
| | | showPageList: [], |
| | | questionData: {}, |
| | | }, |
| | | }); |
| | | pageExample.$mount( |
| | | (this.container ? this.container : document).querySelector( |
| | | "#searchContent" |
| | | ) |
| | | ); |
| | | // 获取页码 |
| | | const pageDom = (this.container ? this.container : document) |
| | | .querySelector("#searchDomBox") |
| | | .querySelectorAll(".page-box"); |
| | | const pages = []; |
| | | for (let i = 0; i < pageDom.length; i++) { |
| | | const pageDomItem = pageDom[i]; |
| | | pages.push(Number(pageDomItem.getAttribute("page"))); |
| | | } |
| | | // 获取页面结束,卸载销毁 |
| | | pageExample.$destroy(); |
| | | (this.container ? this.container : document).querySelector( |
| | | "#searchDomBox" |
| | | ).innerHTML = '<div id="searchContent"></div>'; |
| | | // 遍历页码 |
| | | if (pages.length) { |
| | | for (let i = 0; i < pages.length; i++) { |
| | | const pageNum = pages[i]; |
| | | // 动态渲染对应章节的页码 |
| | | pageComponent = Vue.extend(pageData[key]); |
| | | pageExample = new pageComponent({ |
| | | propsData: { |
| | | showPageList: [pageNum], |
| | | questionData: {}, |
| | | }, |
| | | }); |
| | | pageExample.$mount( |
| | | (this.container ? this.container : document).querySelector( |
| | | "#searchContent" |
| | | ) |
| | | ); |
| | | // 获取对应页面dom |
| | | const thisPageDom = (this.container ? this.container : document) |
| | | .querySelector("#searchDomBox") |
| | | .querySelector(`[page="${pageNum}"]`); |
| | | if (thisPageDom) { |
| | | // 获取页面所有text节点 |
| | | const pageTextList = document.createTreeWalker( |
| | | thisPageDom, |
| | | NodeFilter.SHOW_TEXT |
| | | ); |
| | | // 匹配关键字 |
| | | const allPageTextNodes = []; |
| | | let currentNode = pageTextList.nextNode(); |
| | | while (currentNode) { |
| | | allPageTextNodes.push(currentNode); |
| | | currentNode = pageTextList.nextNode(); |
| | | } |
| | | for (let i = 0; i < allPageTextNodes.length; i++) { |
| | | const textDom = allPageTextNodes[i]; |
| | | let txtIndex = textDom.textContent.indexOf(keyword); |
| | | if (txtIndex > -1) { |
| | | // 记录关键字所在页码、章节以及匹配到的段落 |
| | | searchResult.push({ |
| | | page: pageNum, |
| | | catalog: catalogIndex, |
| | | txt: textDom.textContent, |
| | | txtIndex: txtIndex, |
| | | }); |
| | | } |
| | | } |
| | | // 结束,卸载销毁 |
| | | pageExample.$destroy(); |
| | | (this.container ? this.container : document).querySelector( |
| | | "#searchDomBox" |
| | | ).innerHTML = '<div id="searchContent"></div>'; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | // 输出搜索结果 |
| | | console.log(searchResult); |
| | | return searchResult; |
| | | }, |
| | | |
| | | // 根据检索结果跳转对应位置并高亮 |
| | | searchItemLocation(data) { |
| | | // 记录高亮信息 |
| | | this.highlightData = data; |
| | | // 跳转 |
| | | this.gotoPage(data.catalog, data.page, () => {}); |
| | | }, |
| | | }, |
| | | components: { |
| | | front001, |