| | |
| | | import chapterEleven from "./components/chapter011.vue"; |
| | | import chapterTwelve from "./components/chapter012.vue"; |
| | | import chapterThirteen from "./components/chapter013.vue"; |
| | | import NoteIcon from "@/assets/images/biji.png"; |
| | | import _ from "lodash"; |
| | | export default { |
| | | data() { |
| | |
| | | loadThreshold: 300, // 触发加载阈值 |
| | | throttleThreshold: 100, // 节流阈值 |
| | | previousScrollTop: 0, |
| | | throttledScrollHandler: null |
| | | throttledScrollHandler: null, |
| | | observer: null |
| | | }; |
| | | }, |
| | | watch: { |
| | | showCatalogList: { |
| | | handler(newVal) { |
| | | console.log("显示章节", newVal); |
| | | if (this.$store.state.qiankun && this.$store.state.qiankun.catalogChange) { |
| | | handler(newVal, oldVal) { |
| | | if ( |
| | | this.$store.state.qiankun && |
| | | this.$store.state.qiankun.catalogChange |
| | | ) { |
| | | // 调用父层方法 |
| | | this.$store.state.qiankun.catalogChange({ |
| | | showCatalogList: newVal |
| | | }); |
| | | } |
| | | // 启动页码观察 |
| | | setTimeout(() => { |
| | | this.initObservation(); |
| | | this.initThemeColor(); |
| | | }, 500); |
| | | } |
| | | } |
| | | }, |
| | |
| | | this.throttleThreshold, |
| | | { leading: true, trailing: false } |
| | | ); |
| | | // 提供页面跳转功能 |
| | | // 定义子层方法 |
| | | if (this.setGlobalState) { |
| | | console.log("setGlobalState"); |
| | | // 定义子层方法 |
| | | // 提供页面跳转功能 |
| | | this.setGlobalState({ |
| | | gotoPage: (catalog, page) => { |
| | | console.log(catalog, page, "gotoPage:catalog, page"); |
| | | this.gotoPage(catalog, page); |
| | | }, |
| | | // 渲染笔记、高亮、划线 |
| | | renderSign: (type, data) => { |
| | | this.renderSign(type, data); |
| | | }, |
| | | // 删除笔记、高亮、划线 |
| | | delSign: (data) => { |
| | | this.delSign(data); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 测试页面跳转 |
| | | // 创建一个新的 Intersection Observer 实例,用于观察目标元素和执行相应的回调函数。 |
| | | // new IntersectionObserver(callback, options):使用之前定义的 callback 回调函数和 options 配置选项来初始化 Intersection Observer 实例。 |
| | | this.observer = new IntersectionObserver(this.pageChangeCallback, { |
| | | root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。 |
| | | rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合 |
| | | threshold: 0.5 // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。 |
| | | }); |
| | | |
| | | // 启动页码观察 |
| | | setTimeout(() => { |
| | | this.gotoPage(5, 100); |
| | | }, 3000); |
| | | this.initObservation(); |
| | | this.initThemeColor(); |
| | | }, 500); |
| | | |
| | | // 测试页面跳转 |
| | | // setTimeout(() => { |
| | | // this.gotoPage(5, 100); |
| | | // setTimeout(() => { |
| | | // this.renderSign("Note", { |
| | | // id: "2ACA9359", |
| | | // txt: "营养素和热量,才能", |
| | | // page: "100", |
| | | // type: "Highlight", |
| | | // color: "#F5E12A" |
| | | // }); |
| | | // setTimeout(() => { |
| | | // this.delSign({ |
| | | // ids: ["2ACA9359"] |
| | | // }); |
| | | // }, 2000); |
| | | // }, 1000); |
| | | // }, 3000); |
| | | }, |
| | | methods: { |
| | | scrollFun(e) { |
| | | // 滚动监听 |
| | | scrollFun(event) { |
| | | // 判断向上滚动还是向下滚动 |
| | | if (event.target.scrollTop > this.previousScrollTop) { |
| | | // 向下 |
| | | const currentScrollTop = |
| | | event.target.scrollTop + event.target.offsetHeight; |
| | | if ( |
| | |
| | | } |
| | | } |
| | | } else if (event.target.scrollTop < this.previousScrollTop) { |
| | | // 向上 |
| | | const currentScrollTop = event.target.scrollTop; |
| | | if (currentScrollTop <= this.loadThreshold) { |
| | | // 到达阈值 |
| | |
| | | } |
| | | } |
| | | // showCatalogList 当前显示的三个章节,watch监听传递给主应用 |
| | | console.log(this.showCatalogList); |
| | | // 更新上一次滚动的位置 |
| | | this.previousScrollTop = event.target.scrollTop; |
| | | |
| | | // 返回页码和章节信息 |
| | | if (this.$store.state.qiankun && this.$store.state.qiankun.pageChange) |
| | | this.$store.state.qiankun.pageChange({ |
| | | page: 100, |
| | | catalog: 5, |
| | | catalogId: "", |
| | | catalogName: "" |
| | | }); |
| | | }, |
| | | // 章节、页面跳转 |
| | | gotoPage(catalog, page) { |
| | | if (catalog >= 0 && catalog <= this.catalogLength) { |
| | | // 处理渲染章节 |
| | |
| | | } |
| | | setTimeout(() => { |
| | | // 跳转页码 |
| | | const pageDom = document.querySelector(`[page="${page}"]`); |
| | | const pageDom = ( |
| | | this.container ? this.container : document |
| | | ).querySelector(`[page="${page}"]`); |
| | | if (pageDom) { |
| | | pageDom.scrollIntoView(); |
| | | } else { |
| | | console.log("页码错误!"); |
| | | } |
| | | }, 50); |
| | | }, 500); |
| | | } else { |
| | | console.log("章节错误!"); |
| | | } |
| | | }, |
| | | |
| | | // 渲染标记 |
| | | renderSign(type, data) { |
| | | const existence = ( |
| | | this.container ? this.container : document |
| | | ).querySelector(`[dataid="${data.id}"]`); |
| | | // 去重 |
| | | if (!existence) { |
| | | const pageDom = ( |
| | | this.container ? this.container : document |
| | | ).querySelector(`[page="${data.page}"]`); |
| | | let reg = new RegExp(`${data.txt}`, "ig"); |
| | | switch (type) { |
| | | case "Highlight": |
| | | // 高亮 |
| | | pageDom.innerHTML = pageDom.innerHTML.replace( |
| | | reg, |
| | | `<span datatype="Highlight" dataid="${data.id}" style="background: ${data.color};" class="highLight" onclick="signClick('Highlight','${data.id}','${data.chapterNum}')">${data.txt}</span>` |
| | | ); |
| | | break; |
| | | case "Dashing": |
| | | // 划线 |
| | | pageDom.innerHTML = pageDom.innerHTML.replace( |
| | | reg, |
| | | `<span datatype="Dashing" dataid="${data.id}" style="text-decoration-color:${data.color};" class="underline" onclick="signClick('Dashing','${data.id}','${data.chapterNum}')">${data.txt}</span>` |
| | | ); |
| | | break; |
| | | case "Note": |
| | | // 笔记 |
| | | pageDom.innerHTML = pageDom.innerHTML.replace( |
| | | reg, |
| | | `<span datatype="Note" dataid="${data.id}" style="border-bottom-color:${data.color}" class="notesline" onclick="signClick('Note','${data.id}','${data.chapterNum}')" onmouseover="noteHover('Note','${data.id}','${data.chapterNum}')">${data.txt}<img src="${NoteIcon}" style="cursor: pointer" /></span>` |
| | | ); |
| | | break; |
| | | } |
| | | } |
| | | }, |
| | | // 删除标记渲染 |
| | | delSign({ ids, type }) { |
| | | if (ids && ids.length) { |
| | | for (let i = 0; i < ids.length; i++) { |
| | | const id = ids[i]; |
| | | const dom = ( |
| | | this.container ? this.container : document |
| | | ).querySelector(`[dataid="${id}"]`); |
| | | dom.parentNode.innerHTML = dom.parentNode.innerHTML.replace( |
| | | dom.outerHTML, |
| | | dom.outerText |
| | | ); |
| | | } |
| | | } |
| | | if (type) { |
| | | const doms = ( |
| | | this.container ? this.container : document |
| | | ).querySelectorAll(`[datatype="${type}"]`); |
| | | for (let i = 0; i < doms.length; i++) { |
| | | const dom = doms[i]; |
| | | dom.parentNode.innerHTML = dom.parentNode.innerHTML.replace( |
| | | dom.outerHTML, |
| | | dom.outerText |
| | | ); |
| | | } |
| | | } |
| | | }, |
| | | initObservation() { |
| | | const sections = ( |
| | | this.container ? this.container : document |
| | | ).querySelectorAll(".page-box"); |
| | | sections.forEach((section) => { |
| | | //observer 观察每个元素,以便在它们进入或离开视窗时触发回调函数。 |
| | | const isObserver = section.getAttribute("observer"); |
| | | if (!isObserver) { |
| | | this.observer.observe(section); |
| | | section.setAttribute("observer", "1"); |
| | | } |
| | | }); |
| | | }, |
| | | initThemeColor() { |
| | | // 获取各种需要主题色的节点 |
| | | const colorDom = ( |
| | | this.container ? this.container : document |
| | | ).querySelectorAll(".theme-color"); |
| | | const backgroundColorDom = ( |
| | | this.container ? this.container : document |
| | | ).querySelectorAll(".theme-back"); |
| | | const borderColorDom = ( |
| | | this.container ? this.container : document |
| | | ).querySelectorAll(".theme-border"); |
| | | // 获取配置的主题色 |
| | | const bookThemeColor = |
| | | this.config.activeBook && this.config.activeBook.bookThemeColor |
| | | ? this.config.activeBook.bookThemeColor |
| | | : null; |
| | | const chapterThemeColor = |
| | | this.config.activeBook && this.config.activeBook.chapterThemeColor |
| | | ? this.config.activeBook.chapterThemeColor |
| | | : null; |
| | | const pageThemeColor = |
| | | this.config.activeBook && this.config.activeBook.pageThemeColor |
| | | ? this.config.activeBook.pageThemeColor |
| | | : null; |
| | | colorDom.forEach((domItem) => { |
| | | // 获取章节、页码 |
| | | let pageDom = this.getParentWithClass(domItem, "page-box"); |
| | | let chapterDom = this.getParentWithClass(domItem, "chapter"); |
| | | let page, chapterNum; |
| | | if (pageDom) page = pageDom.getAttribute("page"); |
| | | if (chapterDom) chapterNum = chapterDom.getAttribute("num"); |
| | | // 向上匹配主题色 |
| | | const themeColor = |
| | | page && pageThemeColor && pageThemeColor[page] |
| | | ? pageThemeColor[page] |
| | | : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum] |
| | | ? chapterThemeColor[chapterNum] |
| | | : bookThemeColor; |
| | | if (themeColor) { |
| | | domItem.style.color = themeColor; |
| | | } |
| | | }); |
| | | backgroundColorDom.forEach((domItem) => { |
| | | // 获取章节、页码 |
| | | let pageDom = this.getParentWithClass(domItem, "page-box"); |
| | | let chapterDom = this.getParentWithClass(domItem, "chapter"); |
| | | let page, chapterNum; |
| | | if (pageDom) page = pageDom.getAttribute("page"); |
| | | if (chapterDom) chapterNum = chapterDom.getAttribute("num"); |
| | | // 向上匹配主题色 |
| | | const themeColor = |
| | | page && pageThemeColor && pageThemeColor[page] |
| | | ? pageThemeColor[page] |
| | | : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum] |
| | | ? chapterThemeColor[chapterNum] |
| | | : bookThemeColor; |
| | | if (themeColor) { |
| | | domItem.style.backgroundColor = themeColor; |
| | | } |
| | | }); |
| | | borderColorDom.forEach((domItem) => { |
| | | // 获取章节、页码 |
| | | let pageDom = this.getParentWithClass(domItem, "page-box"); |
| | | let chapterDom = this.getParentWithClass(domItem, "chapter"); |
| | | let page, chapterNum; |
| | | if (pageDom) page = pageDom.getAttribute("page"); |
| | | if (chapterDom) chapterNum = chapterDom.getAttribute("num"); |
| | | // 向上匹配主题色 |
| | | const themeColor = |
| | | page && pageThemeColor && pageThemeColor[page] |
| | | ? pageThemeColor[page] |
| | | : chapterNum && chapterThemeColor && chapterThemeColor[chapterNum] |
| | | ? chapterThemeColor[chapterNum] |
| | | : bookThemeColor; |
| | | if (themeColor) { |
| | | domItem.style.borderColor = themeColor; |
| | | } |
| | | }); |
| | | }, |
| | | getParentWithClass(element, className) { |
| | | while (element.parentElement) { |
| | | element = element.parentElement; |
| | | if (element.classList.contains(className)) { |
| | | return element; |
| | | } |
| | | } |
| | | }, |
| | | pageChangeCallback(entries, observer) { |
| | | //entries:代表观察到的目标元素的集合。 observer:代表观察者对象。 |
| | | entries.forEach((entry) => { |
| | | //entry.isIntersecting:检查当前目标元素是否与根元素相交。 |
| | | if (entry.isIntersecting) { |
| | | const target = entry.target; |
| | | //entry.target:获取当前目标元素 |
| | | const page = target.getAttribute("page"); |
| | | const catalogDom = this.tool.getParentNodeByClassName( |
| | | target, |
| | | "chapter" |
| | | ); |
| | | const catalog = catalogDom.getAttribute("num"); |
| | | console.log("page", page, catalog); |
| | | // 返回页码和章节信息 |
| | | if (this.$store.state.qiankun && this.$store.state.qiankun.pageChange) |
| | | this.$store.state.qiankun.pageChange({ |
| | | page: page, |
| | | catalog: catalog |
| | | }); |
| | | // const sections = Array.from(document.querySelectorAll(".section")); |
| | | //sections:获取所有具有 .section 类名的元素,并转换为数组。 |
| | | // let index = sections.findIndex((section) => section === target) + 1; |
| | | //index:查找当前目标元素在 sections 数组中的索引,并加 1,用于确定当前页码。 |
| | | } |
| | | }); |
| | | } |
| | | }, |
| | | components: { |