zhongshujie
2 天以前 ce70bc450a2401997bb850f89f3c4dc0a23e0a72
src/books/digitalDentalRestorationTechnology/view/components/index.vue
@@ -1,972 +1,771 @@
<template>
    <div class="page-main" @scroll="throttledScrollHandler">
        <div id="searchDomBox" style="display: none">
            <div id="searchContent"></div>
        </div>
        <div class="page-content" :style="{
            fontSize: fontSize + 'px',
            transform: `scale(${pageZoom})`,
            transformOrigin: 'center top',
        }">
            <pageHeader v-if="showCatalogList.indexOf(1) > -1" :showPageList="loadPageList"></pageHeader>
            <chapterOne v-if="showCatalogList.indexOf(2) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterOne>
            <chapterTwo v-if="showCatalogList.indexOf(3) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterTwo>
            <chapterThree v-if="showCatalogList.indexOf(4) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterThree>
            <chapterFour v-if="showCatalogList.indexOf(5) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterFour>
            <chapterFive v-if="showCatalogList.indexOf(6) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterFive>
            <chapterSix v-if="showCatalogList.indexOf(7) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterSix>
            <chapterSeven v-if="showCatalogList.indexOf(8) > -1" :showPageList="loadPageList"
                :resourceList="resourceList">
            </chapterSeven>
        </div>
  <div class="page-main" @scroll="throttledScrollHandler">
    <div id="searchDomBox" style="display: none">
      <div id="searchContent"></div>
    </div>
    <div class="page-content" :style="{
      fontSize: fontSize + 'px',
      transform: `scale(${pageZoom})`,
      transformOrigin: 'center top',
    }">
      <pageHeader v-if="showCatalogList.indexOf(1) > -1" :showPageList="loadPageList"></pageHeader>
      <chapterOne v-if="showCatalogList.indexOf(2) > -1" :showPageList="loadPageList" :getResourceInfo="resourceListFun"
        :interfaceQuestion="bookQuestionsList">
      </chapterOne>
      <chapterTwo v-if="showCatalogList.indexOf(3) > -1" :showPageList="loadPageList" :getResourceInfo="resourceListFun"
        :interfaceQuestion="bookQuestionsList">
      </chapterTwo>
      <chapterThree v-if="showCatalogList.indexOf(4) > -1" :showPageList="loadPageList" :getResourceInfo="resourceListFun"
        :interfaceQuestion="bookQuestionsList">
      </chapterThree>
      <chapterFour v-if="showCatalogList.indexOf(5) > -1" :showPageList="loadPageList"
        :getResourceInfo="resourceListFun" :interfaceQuestion="bookQuestionsList">
      </chapterFour>
      <chapterFive v-if="showCatalogList.indexOf(6) > -1" :showPageList="loadPageList"
        :getResourceInfo="resourceListFun" :interfaceQuestion="bookQuestionsList">
      </chapterFive>
      <chapterSix v-if="showCatalogList.indexOf(7) > -1" :showPageList="loadPageList" :getResourceInfo="resourceListFun"
        :interfaceQuestion="bookQuestionsList">
      </chapterSix>
      <chapterSeven v-if="showCatalogList.indexOf(8) > -1" :showPageList="loadPageList"
        :getResourceInfo="resourceListFun" :interfaceQuestion="bookQuestionsList">
      </chapterSeven>
    </div>
  </div>
</template>
<script>
import Vue from "vue";
import pageHeader from "./header.vue";
import chapterOne from "./chapter001.vue"
import chapterTwo from "./chapter002.vue"
import chapterThree from "./chapter003.vue"
import chapterFour from "./chapter004.vue"
import chapterFive from "./chapter005.vue"
import chapterSix from "./chapter006.vue"
import chapterSeven from "./chapter007.vue"
import chapterOne from "./chapter001.vue";
import chapterTwo from "./chapter002.vue";
import chapterThree from "./chapter003.vue";
import chapterFour from "./chapter004.vue";
import chapterFive from "./chapter005.vue";
import chapterSix from "./chapter006.vue";
import chapterSeven from "./chapter007.vue";
import NoteIcon from "@/assets/images/biji.png";
import MG from "@/assets/js/middleGround/WebMiddleGroundApi";
import _ from "lodash";
import Swiper from "swiper/bundle";
import "swiper/swiper-bundle.css";
import Viewer from "viewerjs";
import "viewerjs/dist/viewer.css";
export default {
    name: "pageContent",
    data() {
        return {
            catalogLength: 8, // 总章节数
            showCatalogList: [], // 显示的章节
            loadThreshold: 300, // 触发加载阈值
            throttleThreshold: 100, // 节流阈值
            previousScrollTop: 0,
            throttledScrollHandler: null,
            observer: null,
            loadPageObserver: null,
            loadPageList: [],
            questionDataMap: {},
            renderSignMap: {},
            highlightData: null,
            audioPath: "",
            currentTime: null,
            videoList: [],
            resourceList: {},
        };
  name: "pageContent",
  data() {
    return {
      catalogLength: 8, // 总章节数
      showCatalogList: [], // 显示的章节
      loadThreshold: 300, // 触发加载阈值
      throttleThreshold: 100, // 节流阈值
      previousScrollTop: 0,
      throttledScrollHandler: null,
      observer: null,
      loadPageObserver: null,
      loadPageList: [],
      questionDataMap: {},
      renderSignMap: {},
      highlightData: null,
      audioPath: "",
      currentTime: null,
      videoList: [],
      resourceList: [],
      bookQuestionsList: [],
    };
  },
  computed: {
    fontSize() {
      this.transformDom(this.$store.state.qiankun.fontSize);
      return this.$store.state.qiankun.fontSize
        ? this.$store.state.qiankun.fontSize
        : 14;
    },
    computed: {
        fontSize() {
            this.transformDom(this.$store.state.qiankun.fontSize);
            return this.$store.state.qiankun.fontSize
                ? this.$store.state.qiankun.fontSize
                : 14;
        },
        pageZoom() {
            return this.$store.state.qiankun.scale
                ? this.$store.state.qiankun.scale / 100
                : 1;
        },
    pageZoom() {
      return this.$store.state.qiankun.scale
        ? this.$store.state.qiankun.scale / 100
        : 1;
    },
    watch: {
        showCatalogList: {
            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);
            },
        },
        loadPageList: {
            handler(newVal, oldVal) {
                setTimeout(() => {
                    this.transformDom(this.$store.state.qiankun.fontSize);
                    this.initSwiper();
                    this.initViewer();
                    this.closeAudio();
                    this.closeVideo();
                }, 200);
            },
        },
        pageZoom: {
            handler(newVal, oldVal) {
                const scrollBox = (
                    this.container ? this.container : document
                ).querySelector(".page-main");
                scrollBox.scrollTop = (scrollBox.scrollTop / oldVal) * newVal;
            },
        },
        resourceList: {
            handler(newVal, oldVal) {
                this.resourceList = newVal;
            },
        },
    },
    mounted() {
        // 默认加载章节
        this.showCatalogList = [1];
        // 滚动监听节流
        this.throttledScrollHandler = _.throttle(
            this.scrollFun,
            this.throttleThreshold,
            { leading: true, trailing: false }
        );
        // 定义子层方法
        if (this.setGlobalState) {
            // 提供页面跳转功能
            this.setGlobalState({
                gotoPage: (catalog, page) => {
                    this.gotoPage(catalog, page);
                },
                // 渲染笔记、高亮、划线
                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);
                },
            });
  },
  watch: {
    showCatalogList: {
      handler(newVal, oldVal) {
        if (
          this.$store.state.qiankun &&
          this.$store.state.qiankun.catalogChange
        ) {
          // 调用父层方法
          this.$store.state.qiankun.catalogChange({
            showCatalogList: newVal,
          });
        }
        // 创建一个新的 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,表示当目标元素一半或更多显示在视窗中时触发回调函数。
        });
        this.loadPageObserver = new IntersectionObserver(this.loadPageCallback, {
            root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
            rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
            threshold: 0, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
        });
        // this.getBookResourceList();
        // 启动页码观察
        setTimeout(() => {
            this.initObservation();
            this.initThemeColor();
          this.initObservation();
        }, 500);
        // 测试页面跳转
        // setTimeout(() => {
        //     this.gotoPage(8, 143);
        // }, 500);
        // const pageDom = (this.container ? this.container : document)
        //   .querySelector("#app")
        //   .querySelectorAll(".page-box");
        // 检索
        // console.log(this.searchTextByPage("保护内脏器官"), "searchTextByPage");
        // 检索跳转
        // this.searchItemLocation({
        //   catalog: 2,
        //   page: 10,
        //   txt: " 运动系统是由骨、骨连结和骨骼肌三部分组成的。全身的骨通过骨连结组成人体骨骼(见图1-1)。骨骼是人体的支架,具有保护内脏器官、供肌肉附着和作为肌肉运动的杠杆等作用。在神经系统的支配下,肌肉收缩牵动所附着的骨绕着关节转动,使身体产生各种动作。所以,运动系统具有运动、支持和保护等功能,幼年时期的骨骼还具有造血功能。 ",
        //   txtIndex: 57
        // });
        // }, 500);
      },
    },
    methods: {
        // setZoom1() {
        //   let scale = this.$store.state.qiankun.scale + 10;
        //   const scrollBox = (
        //     this.container ? this.container : document
        //   ).querySelector(".page-main");
        //   this.$store.commit("setZoom", scale);
        // },
        // setZoom2() {
        //   let scale = this.$store.state.qiankun.scale - 10;
        //   const scrollBox = (
        //     this.container ? this.container : document
        //   ).querySelector(".page-main");
        //   this.$store.commit("setZoom", scale);
        // },
        // 请求资源Json
        async getBookResourceList() {
            this.resourceList = await this.config.getBookResources(
                process.env.VUE_APP_RESOURCE_CTX + (process.env.VUE_APP_ENV == "product"
                    ? process.env.VUE_APP_BOOK_ID
                    : "clinicalDiseasesSummary")
    loadPageList: {
      handler(newVal, oldVal) {
        setTimeout(() => {
          this.transformDom(this.$store.state.qiankun.fontSize);
          this.initSwiper();
          this.initViewer();
          this.closeAudio();
          this.closeVideo();
          this.initThemeColor();
        }, 200);
      },
    },
    pageZoom: {
      handler(newVal, oldVal) {
        const scrollBox = (
          this.container ? this.container : document
        ).querySelector(".page-main");
        scrollBox.scrollTop = (scrollBox.scrollTop / oldVal) * newVal;
      },
    },
    resourceList: {
      handler(newVal, oldVal) {
        this.resourceList = newVal;
      },
    },
    bookQuestionsList: {
      handler(newVal, oldVal) {
        this.bookQuestionsList = newVal;
      },
    },
  },
  mounted() {
    // 默认加载章节
    this.showCatalogList = [1];
    // 滚动监听节流
    this.throttledScrollHandler = _.throttle(
      this.scrollFun,
      this.throttleThreshold,
      { leading: true, trailing: false }
    );
    // 定义子层方法
    if (this.setGlobalState) {
      // 提供页面跳转功能
      this.setGlobalState({
        gotoPage: (catalog, page) => {
          this.gotoPage(catalog, page);
        },
        // 渲染笔记、高亮、划线
        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);
        },
      });
    }
    // 创建一个新的 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,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    this.loadPageObserver = new IntersectionObserver(this.loadPageCallback, {
      root: null, // 指定根元素,这里设为 null,表示选取整个视窗作为根元素。
      rootMargin: "0px", // 指定根元素的边界,这里设为 "0px",表示根元素的边界和视窗的边界重合
      threshold: 0, // 指定交叉比例,这里设为 0.5,表示当目标元素一半或更多显示在视窗中时触发回调函数。
    });
    this.getBookResourceList();
    // 获取整本书题目
    this.getBookQuestionList();
    // 启动页码观察
    setTimeout(() => {
      this.initObservation();
    }, 500);
    // 测试页面跳转
    // setTimeout(() => {
    //   this.gotoPage(7, 125);
    // }, 500);
  },
  methods: {
    // 请求资源Json
    getBookResourceList() {
      this.config
        .getBookResources(
          process.env.VUE_APP_RESOURCE_CTX +
          (process.env.VUE_APP_ENV == "product"
            ? process.env.VUE_APP_BOOK_ID
            : "digitalDentalRestorationTechnology")
        )
        .then((data) => {
          this.resourceList = data;
        })
        .catch((error) => {
          console.error("获取图书资源列表失败:", error);
        });
    },
    // 获取图书问题列表
    getBookQuestionList() {
      let query = {
        storeInfo: this.config.activeBook.storeRefcode,
        path: "*",
        cmsPath: this.config.activeBook.rootCmsItemId,
        cmsType: "*",
        productId: this.config.activeBook.bookId,
        queryType: "*",
        itemFields: {
          Embedded_QuestionBank_Stem: [],
          Embedded_QuestionBank_AnalysisCon: [],
          Embedded_QuestionBank_Answer: [],
          Embedded_QuestionBank_Option: [],
          Embedded_QuestionBank_QuestionType: [],
          Embedded_QuestionBank_StemStyle: [],
          Embedded_QuestionBank_OptionStyle: [],
          Embedded_QuestionBank_KnowledgePoint: [],
          Embedded_QuestionBank_Difficulty: [],
        },
      };
      MG.store
        .getProductDetail(query)
        .then((res) => {
          let bookQuestionList = [];
          if (res.datas.cmsDatas[0].datas.length > 0) {
            res.datas.cmsDatas[0].datas.forEach((item) => {
              if (item.datas.Type === "questionBankItem") {
                bookQuestionList.push(item);
              }
            });
          }
          this.bookQuestionsList = bookQuestionList;
        })
        .catch((error) => {
          console.error("获取图书问题列表失败:", error);
        });
    },
    resourceListFun(id, key) {
      let data = this.resourceList.find(item => item.key == id)
      return key ? data[key] : data
    },
    // 滚动监听
    scrollFun(event) {
      this.handleVideoPicture();
      // 判断向上滚动还是向下滚动
      if (event.target.scrollTop > this.previousScrollTop) {
        this.getAduio();
        // 向下
        const currentScrollTop =
          event.target.scrollTop + event.target.offsetHeight;
        if (
          currentScrollTop >=
          event.target.scrollHeight - this.loadThreshold
        ) {
          // 到达阈值
          if (
            this.showCatalogList[this.showCatalogList.length - 1] <
            this.catalogLength
          ) {
            // 加载下一章
            this.showCatalogList.push(
              this.showCatalogList[this.showCatalogList.length - 1] + 1
            );
        },
        // 滚动监听
        scrollFun(event) {
            this.handleVideoPicture();
            // 判断向上滚动还是向下滚动
            if (event.target.scrollTop > this.previousScrollTop) {
                this.getAduio();
                // 向下
                const currentScrollTop =
                    event.target.scrollTop + event.target.offsetHeight;
                if (
                    currentScrollTop >=
                    event.target.scrollHeight - this.loadThreshold
                ) {
                    console.log(1);
                    // 到达阈值
                    if (
                        this.showCatalogList[this.showCatalogList.length - 1] <
                        this.catalogLength
                    ) {
                        // 加载下一章
                        this.showCatalogList.push(
                            this.showCatalogList[this.showCatalogList.length - 1] + 1
                        );
                        if (this.showCatalogList.length > 3) {
                            // 超过三章隐藏顶部一章
                            this.showCatalogList.shift();
                        }
                    }
                }
            } else if (event.target.scrollTop < this.previousScrollTop) {
                this.handleAudio();
                // 向上
                const currentScrollTop = event.target.scrollTop;
                if (currentScrollTop <= this.loadThreshold) {
                    // 到达阈值
                    if (this.showCatalogList[0] > 0) {
                        // 加载上一章
                        this.showCatalogList.unshift(this.showCatalogList[0] - 1);
                        if (this.showCatalogList.length > 3) {
                            // 超过三章隐藏底部一章
                            this.showCatalogList.pop();
                        }
                    }
                }
            if (this.showCatalogList.length > 3) {
              // 超过三章隐藏顶部一章
              this.showCatalogList.shift();
            }
            // showCatalogList 当前显示的三个章节,watch监听传递给主应用
            // 更新上一次滚动的位置
            this.previousScrollTop = event.target.scrollTop;
        },
        // 章节、页面跳转
        gotoPage(catalog, page) {
            if (catalog >= 0 && catalog <= this.catalogLength) {
                // 处理渲染章节
                if (catalog == 0) {
                    this.showCatalogList = [0, 1];
                } else if (catalog == this.catalogLength) {
                    this.showCatalogList = [
                        this.catalogLength - 2,
                        this.catalogLength - 1,
                        this.catalogLength,
                    ];
                } else {
                    this.showCatalogList = [catalog - 1, catalog, catalog + 1];
                }
                setTimeout(() => {
                    // 跳转页码
                    const pageDom = (
                        this.container ? this.container : document
                    ).querySelector(`[page="${page}"]`);
                    if (pageDom) {
                        pageDom.scrollIntoView();
                    } else {
                        console.log("页码错误!");
                    }
                }, 500);
            } else {
                console.log("章节错误!");
          }
        }
      } else if (event.target.scrollTop < this.previousScrollTop) {
        this.handleAudio();
        // 向上
        const currentScrollTop = event.target.scrollTop;
        if (currentScrollTop <= this.loadThreshold) {
          // 到达阈值
          if (this.showCatalogList[0] > 0) {
            // 加载上一章
            this.showCatalogList.unshift(this.showCatalogList[0] - 1);
            if (this.showCatalogList.length > 3) {
              // 超过三章隐藏底部一章
              this.showCatalogList.pop();
            }
        },
          }
        }
      }
      // showCatalogList 当前显示的三个章节,watch监听传递给主应用
      // 更新上一次滚动的位置
      this.previousScrollTop = event.target.scrollTop;
    },
    // 章节、页面跳转
    gotoPage(catalog, page) {
      if (catalog >= 0 && catalog <= this.catalogLength) {
        // 处理渲染章节
        if (catalog == 0) {
          this.showCatalogList = [0, 1];
        } else if (catalog == this.catalogLength) {
          this.showCatalogList = [
            this.catalogLength - 2,
            this.catalogLength - 1,
            this.catalogLength,
          ];
        } else {
          this.showCatalogList = [catalog - 1, catalog, catalog + 1];
        }
        setTimeout(() => {
          // 跳转页码
          const pageDom = (
            this.container ? this.container : document
          ).querySelector(`[page="${page}"]`);
          if (pageDom) {
            pageDom.scrollIntoView();
          } else {
            console.log("页码错误!");
          }
        }, 500);
      } else {
        console.log("章节错误!");
      }
    },
        // 处理标记数据
        handelSignData(type, data) {
            if (this.loadPageList.indexOf(Number(data.page)) > -1) {
                // 立即渲染
                this.renderSign(type, data);
    // 处理标记数据
    handelSignData(type, data) {
      if (this.loadPageList.indexOf(Number(data.page)) > -1) {
        // 立即渲染
        this.renderSign(type, data);
      }
      // 储存数据
      if (!this.renderSignMap[type]) this.renderSignMap[type] = {};
      if (!this.renderSignMap[type][data.page])
        this.renderSignMap[type][data.page] = [];
      this.renderSignMap[type][data.page].push(data);
    },
    // 渲染标记
    renderSign(type, data) {
      // 父层设置禁止渲染标记时不再进行渲染
      if (this.$store.state.qiankun.disableSign) {
        return false;
      }
      const existence = (
        this.container ? this.container : document
      ).querySelector(`[dataid="${data.id}"]`);
      // 去重
      if (!existence) {
        const pageDom = (
          this.container ? this.container : document
        ).querySelector(`[page="${data.page}"]`);
        // 创建 createTreeWalker 迭代器,用于遍历文本节点,保存到一个数组
        const treeWalker = document.createTreeWalker(
          pageDom,
          NodeFilter.SHOW_TEXT
        );
        const allTextNodes = [];
        let currentNode = treeWalker.nextNode();
        while (currentNode) {
          allTextNodes.push(currentNode);
          currentNode = treeWalker.nextNode();
        }
        for (let i = 0; i < allTextNodes.length; i++) {
          const textDom = allTextNodes[i];
          if (textDom.textContent.indexOf(data.txt) > -1) {
            let reg = new RegExp(`${data.txt}`, "ig");
            switch (type) {
              case "Highlight":
                // 高亮
                textDom.parentNode.innerHTML =
                  textDom.parentNode.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":
                // 划线
                textDom.parentNode.innerHTML =
                  textDom.parentNode.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":
                // 笔记
                textDom.parentNode.innerHTML =
                  textDom.parentNode.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}')" onmouseout="noteOut('Note')">${data.txt}<img src="${NoteIcon}"/></span>`
                  );
                break;
            }
            // 储存数据
            if (!this.renderSignMap[type]) this.renderSignMap[type] = {};
            if (!this.renderSignMap[type][data.page])
                this.renderSignMap[type][data.page] = [];
            this.renderSignMap[type][data.page].push(data);
        },
        // 渲染标记
        renderSign(type, data) {
            // 父层设置禁止渲染标记时不再进行渲染
            if (this.$store.state.qiankun.disableSign) {
                return false;
          }
        }
      }
    },
    // 删除标记渲染
    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) => {
        if (this.config.activeBook && this.config.activeBook.tryPageCount) {
          const page = section.getAttribute("page");
          if (Number(page) > this.config.activeBook.tryPageCount) {
            let chapterDom = this.getParentWithClass(section, "chapter");
            const chapterNum = chapterDom.getAttribute("num");
            this.catalogLength = Number(chapterNum) - 1;
            section.remove();
            return false;
          }
        }
        // observer 观察每个元素,以便在它们进入或离开视窗时触发回调函数。
        const isObserver = section.getAttribute("observer");
        const isLoadObserver = section.getAttribute("loadObserver");
        if (!isObserver) {
          this.observer.observe(section);
          section.setAttribute("observer", "1");
        }
        if (!isLoadObserver) {
          this.loadPageObserver.observe(section);
          section.setAttribute("loadObserver", "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");
          let text = null;
          if (target.querySelector("p")) {
            text = target.querySelector("p").textContent.substring(0, 50);
          }
          // 返回页码和章节信息
          if (this.$store.state.qiankun && this.$store.state.qiankun.pageChange)
            this.$store.state.qiankun.pageChange({
              page: page,
              catalog: catalog,
              text,
            });
          // const sections = Array.from(document.querySelectorAll(".section"));
          //sections:获取所有具有 .section 类名的元素,并转换为数组。
          // let index = sections.findIndex((section) => section === target) + 1;
          //index:查找当前目标元素在 sections 数组中的索引,并加 1,用于确定当前页码。
        }
      });
    },
    loadPageCallback(entries, observer) {
      entries.forEach(async (entry) => {
        if (entry.isIntersecting) {
          const target = entry.target;
          const page = target.getAttribute("page");
          if (this.loadPageList.indexOf(Number(page)) == -1) {
            const catalogDom = this.tool.getParentNodeByClassName(
              target,
              "chapter"
            );
            // 添加页码
            this.loadPageList.push(Number(page));
            const catalog = catalogDom.getAttribute("num");
            // if (!this.questionDataMap[page]) {
            //   if (testData && testData[catalog]) {
            //     if (testData[catalog][page]) {
            //       if (Array.isArray(testData[catalog][page])) {
            //         this.questionDataMap[page] = await getQuestionList(
            //           page,
            //           testData[catalog][page],
            //           this.config.activeBook
            //         );
            //       } else {
            //         const obj = {};
            //         for (let key in testData[catalog][page]) {
            //           obj[key] = await getQuestionList(
            //             [],
            //             testData[catalog][page][key],
            //             this.config.activeBook
            //           );
            //         }
            //         this.questionDataMap[page] = obj;
            //       }
            //       console.log("题目", this.questionDataMap);
            //     }
            //   }
            // }
            // 渲染这一页的标记
            for (const key in this.renderSignMap) {
              if (this.renderSignMap[key][page]) {
                this.renderSignMap[key][page].forEach((item) => {
                  this.renderSign(key, item);
                });
              }
            }
            const existence = (
                this.container ? this.container : document
            ).querySelector(`[dataid="${data.id}"]`);
            // 去重
            if (!existence) {
                const pageDom = (
                    this.container ? this.container : document
                ).querySelector(`[page="${data.page}"]`);
                // 创建 createTreeWalker 迭代器,用于遍历文本节点,保存到一个数组
                const treeWalker = document.createTreeWalker(
                    pageDom,
                    NodeFilter.SHOW_TEXT
            // 处理高亮
            if (this.highlightData) {
              // 高亮行
              setTimeout(() => {
                // 获取页面所有text节点
                const pageTextList = document.createTreeWalker(
                  target,
                  NodeFilter.SHOW_TEXT
                );
                const allTextNodes = [];
                let currentNode = treeWalker.nextNode();
                // 匹配关键字
                const allPageTextNodes = [];
                let currentNode = pageTextList.nextNode();
                while (currentNode) {
                    allTextNodes.push(currentNode);
                    currentNode = treeWalker.nextNode();
                  allPageTextNodes.push(currentNode);
                  currentNode = pageTextList.nextNode();
                }
                for (let i = 0; i < allTextNodes.length; i++) {
                    const textDom = allTextNodes[i];
                    if (textDom.textContent.indexOf(data.txt) > -1) {
                        let reg = new RegExp(`${data.txt}`, "ig");
                        switch (type) {
                            case "Highlight":
                                // 高亮
                                textDom.parentNode.innerHTML =
                                    textDom.parentNode.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":
                                // 划线
                                textDom.parentNode.innerHTML =
                                    textDom.parentNode.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":
                                // 笔记
                                textDom.parentNode.innerHTML =
                                    textDom.parentNode.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}')" onmouseout="noteOut('Note')">${data.txt}<img src="${NoteIcon}"/></span>`
                                    );
                                break;
                        }
                    }
                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);
            }
        },
        // 删除标记渲染
        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 (this.loadPageList.length > 5) {
              // 超过5页
              this.loadPageList.shift();
            }
            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) => {
                if (this.config.activeBook && this.config.activeBook.tryPageCount) {
                    const page = section.getAttribute("page");
                    if (Number(page) > this.config.activeBook.tryPageCount) {
                        let chapterDom = this.getParentWithClass(section, "chapter");
                        const chapterNum = chapterDom.getAttribute("num");
                        this.catalogLength = Number(chapterNum) - 1;
                        section.remove();
                        return false;
                    }
                }
                // observer 观察每个元素,以便在它们进入或离开视窗时触发回调函数。
                const isObserver = section.getAttribute("observer");
                const isLoadObserver = section.getAttribute("loadObserver");
                if (!isObserver) {
                    this.observer.observe(section);
                    section.setAttribute("observer", "1");
                }
                if (!isLoadObserver) {
                    this.loadPageObserver.observe(section);
                    section.setAttribute("loadObserver", "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");
                    let text = null;
                    if (target.querySelector("p")) {
                        text = target.querySelector("p").textContent.substring(0, 50);
                    }
                    // 返回页码和章节信息
                    if (this.$store.state.qiankun && this.$store.state.qiankun.pageChange)
                        this.$store.state.qiankun.pageChange({
                            page: page,
                            catalog: catalog,
                            text,
                        });
                    // const sections = Array.from(document.querySelectorAll(".section"));
                    //sections:获取所有具有 .section 类名的元素,并转换为数组。
                    // let index = sections.findIndex((section) => section === target) + 1;
                    //index:查找当前目标元素在 sections 数组中的索引,并加 1,用于确定当前页码。
                }
            });
        },
        loadPageCallback(entries, observer) {
            entries.forEach(async (entry) => {
                if (entry.isIntersecting) {
                    const target = entry.target;
                    const page = target.getAttribute("page");
                    if (this.loadPageList.indexOf(Number(page)) == -1) {
                        const catalogDom = this.tool.getParentNodeByClassName(
                            target,
                            "chapter"
                        );
                        // 添加页码
                        this.loadPageList.push(Number(page));
                        const catalog = catalogDom.getAttribute("num");
                        // if (!this.questionDataMap[page]) {
                        //   if (testData && testData[catalog]) {
                        //     if (testData[catalog][page]) {
                        //       if (Array.isArray(testData[catalog][page])) {
                        //         this.questionDataMap[page] = await getQuestionList(
                        //           page,
                        //           testData[catalog][page],
                        //           this.config.activeBook
                        //         );
                        //       } else {
                        //         const obj = {};
                        //         for (let key in testData[catalog][page]) {
                        //           obj[key] = await getQuestionList(
                        //             [],
                        //             testData[catalog][page][key],
                        //             this.config.activeBook
                        //           );
                        //         }
                        //         this.questionDataMap[page] = obj;
                        //       }
                        //       console.log("题目", this.questionDataMap);
                        //     }
                        //   }
                        // }
                        // 渲染这一页的标记
                        for (const key in this.renderSignMap) {
                            if (this.renderSignMap[key][page]) {
                                this.renderSignMap[key][page].forEach((item) => {
                                    this.renderSign(key, item);
                                });
                            }
                        }
                        // 处理高亮
                        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
            ).querySelectorAll(".swiper-img");
            for (let i = 0; i < doms.length; i++) {
                const dom = doms[i];
                new Swiper(dom, {
                    loop: false, // 无缝
                    autoplay: {
                        //自动开始
                        delay: 3000, //时间间隔
                        disableOnInteraction: false, //*手动操作轮播图后不会暂停*
                    },
                    paginationClickable: true,
                    slidesPerView: 1, // 一组三个
                    spaceBetween: 30, // 间隔
                    // 如果需要前进后退按钮
                    navigation: {
                        nextEl: dom.querySelector(".swiper-button-next"),
                        prevEl: dom.querySelector(".swiper-button-prev"),
                    },
                    // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
                    // observer: true,
                    // observeParents: true
                    // // 如果需要分页器
                    // pagination: {
                    //   el: (this.container ? this.container : document).querySelector(
                    //     ".swiper-pagination"
                    //   ),
                    //   clickable: true // 分页器可以点击
                    // }
                });
            }
            const pptDoms = (
                this.container ? this.container : document
            ).querySelectorAll(".swiper_ppt");
            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: dom.querySelector(".swiper-button-next"),
                        prevEl: dom.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;
                        },
                        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
            ).querySelectorAll(".openImgBox");
            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, // 显示标题
                });
            }
        },
        // 根据关键字全文检索
        searchTextByPage(keyword) {
            const searchResult = [];
            let catalogIndex = 0;
            // 所有章节组件(每本书制作时单独配置)
            const pageData = {
                pageHeader,
                chapterOne,
                chapterTwo,
                chapterThree,
                chapterFour,
                chapterFive,
                chapterSix,
                chapterSeven
            };
            // 遍历所有章节文件
            for (const key in pageData) {
                catalogIndex++;
                let pageComponent, pageExample;
                // 先渲染一次当前章节文件(这时页面的内容为空),获取页码信息
                pageComponent = Vue.extend(pageData[key]);
                pageExample = new pageComponent({
                    propsData: {
                        showPageList: [],
                        questionData: {},
                        isSearch: true,
                    },
                });
                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: {},
                                isSearch: true,
                            },
                        });
                        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, () => { });
        },
        // 页面向下滚动,音频小窗播放功能
        getAduio() {
            let allVideo = (
                this.container ? this.container : document
            ).querySelectorAll(".audio");
            allVideo = Array.from(allVideo);
            this.videoList = allVideo;
            if (allVideo.length) {
                // 查找播放状态的最后一条音频
                const playAudio = allVideo
                    .reverse()
                    .find((item) => item.paused == false);
                if (playAudio) {
                    const bottomGap = playAudio.getBoundingClientRect().bottom;
                    if (bottomGap < 0) {
                        playAudio.pause();
                        this.audioPath = playAudio.src;
                        this.currentTime = playAudio.currentTime;
                    }
                }
            }
        },
        // 页面向上滚动,音频小窗回收
        handleAudio() {
            if (!this.audioPath) return false;
            let allVideo = (
                this.container ? this.container : document
            ).querySelectorAll(".audio");
            allVideo = Array.from(allVideo);
            if (allVideo.length) {
                //查找与小窗播放音频同源的页面audio DOM
                const playAudio = allVideo.find((item) => item.src == this.audioPath);
                if (playAudio) {
                    const bottomGap = playAudio.getBoundingClientRect().bottom;
                    if (bottomGap >= 0) {
                        if (this.$refs.audioPlayer) {
                            const playerState = this.$refs.audioPlayer.getVideoPlayer();
                            this.audioPath = "";
                            playAudio.currentTime = playerState.currentTime;
                            if (!playerState.paused) playAudio.play();
                        }
                    }
                }
            }
        },
        // 关闭mini video
        closeMiniAudio() {
            this.audioPath = "";
        },
        // 点击音频播放,关闭其他音频
        closeAudio() {
            let allAudio = (
                this.container ? this.container : document
            ).querySelectorAll(".audio");
            for (let index = 0; index < allAudio.length; index++) {
                const item = allAudio[index];
                item.addEventListener("play", () => {
                    const audioList = Array.from(allAudio);
                    for (let cindex = 0; cindex < audioList.length; cindex++) {
                        const citem = audioList[cindex];
                        if (citem.currentSrc != item.src) {
                            citem.pause();
                        }
                    }
                    this.closeMiniAudio();
                });
            }
        },
        // 点击视频关闭其他
        closeVideo() {
            let allVideo = (
                this.container ? this.container : document
            ).querySelectorAll(".video");
            for (let index = 0; index < allVideo.length; index++) {
                const item = allVideo[index];
                item.addEventListener("playing", (item) => {
                    const path = item.srcElement.src;
                    const videoList = Array.from(allVideo);
                    for (let cindex = 0; cindex < videoList.length; cindex++) {
                        const citem = videoList[cindex];
                        if (citem.currentSrc != path && path) {
                            citem.pause();
                        }
                    }
                });
            }
        },
        // 视频小窗
        handleVideoPicture() {
            let doms = (this.container ? this.container : document).querySelectorAll(
                ".video"
            );
            doms = Array.from(doms);
            if (!doms.length) return false;
            const playVudio = doms.reverse().find((item) => item.paused == false);
            if (playVudio) {
                const bottomGap = playVudio.getBoundingClientRect().bottom;
                const topGap = playVudio.getBoundingClientRect().top;
                if (bottomGap < 0 || topGap > window.innerHeight) {
                    try {
                        if (playVudio.readyState) playVudio.requestPictureInPicture();
                    } catch (error) {
                        console.log(error, "小窗错误error");
                    }
                }
            }
        },
        //其他类名下字体大小变化
        transformDom(fs) {
            if (!fs) return;
            let doms = (this.container ? this.container : document).querySelectorAll(
                ".block"
            );
            if (!doms.length) return;
            for (let index = 0; index < doms.length; index++) {
                const dom = doms[index];
                dom.style.fontSize = fs + "px";
            }
        },
          }
        }
      });
    },
    components: {
    initSwiper() {
      const doms = (
        this.container ? this.container : document
      ).querySelectorAll(".swiper-img");
      for (let i = 0; i < doms.length; i++) {
        const dom = doms[i];
        new Swiper(dom, {
          loop: false, // 无缝
          autoplay: {
            //自动开始
            delay: 3000, //时间间隔
            disableOnInteraction: false, //*手动操作轮播图后不会暂停*
          },
          paginationClickable: true,
          slidesPerView: 1, // 一组三个
          spaceBetween: 30, // 间隔
          // 如果需要前进后退按钮
          navigation: {
            nextEl: dom.querySelector(".swiper-button-next"),
            prevEl: dom.querySelector(".swiper-button-prev"),
          },
          // 窗口变化,重新init,针对F11全屏和放大缩小,必须加
          // observer: true,
          // observeParents: true
          // // 如果需要分页器
          // pagination: {
          //   el: (this.container ? this.container : document).querySelector(
          //     ".swiper-pagination"
          //   ),
          //   clickable: true // 分页器可以点击
          // }
        });
      }
      const pptDoms = (
        this.container ? this.container : document
      ).querySelectorAll(".swiper_ppt");
      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: dom.querySelector(".swiper-button-next"),
            prevEl: dom.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;
            },
            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
      ).querySelectorAll(".openImgBox");
      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, // 显示标题
        });
      }
    },
    // 根据关键字全文检索
    searchTextByPage(keyword) {
      const searchResult = [];
      let catalogIndex = 0;
      // 所有章节组件(每本书制作时单独配置)
      const pageData = {
        pageHeader,
        chapterOne,
        chapterTwo,
@@ -974,22 +773,252 @@
        chapterFour,
        chapterFive,
        chapterSix,
        chapterSeven
        chapterSeven,
      };
      // 遍历所有章节文件
      for (const key in pageData) {
        catalogIndex++;
        let pageComponent, pageExample;
        // 先渲染一次当前章节文件(这时页面的内容为空),获取页码信息
        pageComponent = Vue.extend(pageData[key]);
        pageExample = new pageComponent({
          propsData: {
            showPageList: [],
            questionData: {},
            isSearch: true,
          },
        });
        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: {},
                isSearch: true,
              },
            });
            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, () => { });
    },
    // 页面向下滚动,音频小窗播放功能
    getAduio() {
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      allVideo = Array.from(allVideo);
      this.videoList = allVideo;
      if (allVideo.length) {
        // 查找播放状态的最后一条音频
        const playAudio = allVideo
          .reverse()
          .find((item) => item.paused == false);
        if (playAudio) {
          const bottomGap = playAudio.getBoundingClientRect().bottom;
          if (bottomGap < 0) {
            playAudio.pause();
            this.audioPath = playAudio.src;
            this.currentTime = playAudio.currentTime;
          }
        }
      }
    },
    // 页面向上滚动,音频小窗回收
    handleAudio() {
      if (!this.audioPath) return false;
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      allVideo = Array.from(allVideo);
      if (allVideo.length) {
        //查找与小窗播放音频同源的页面audio DOM
        const playAudio = allVideo.find((item) => item.src == this.audioPath);
        if (playAudio) {
          const bottomGap = playAudio.getBoundingClientRect().bottom;
          if (bottomGap >= 0) {
            if (this.$refs.audioPlayer) {
              const playerState = this.$refs.audioPlayer.getVideoPlayer();
              this.audioPath = "";
              playAudio.currentTime = playerState.currentTime;
              if (!playerState.paused) playAudio.play();
            }
          }
        }
      }
    },
    // 关闭mini video
    closeMiniAudio() {
      this.audioPath = "";
    },
    // 点击音频播放,关闭其他音频
    closeAudio() {
      let allAudio = (
        this.container ? this.container : document
      ).querySelectorAll(".audio");
      for (let index = 0; index < allAudio.length; index++) {
        const item = allAudio[index];
        item.addEventListener("play", () => {
          const audioList = Array.from(allAudio);
          for (let cindex = 0; cindex < audioList.length; cindex++) {
            const citem = audioList[cindex];
            if (citem.currentSrc != item.src) {
              citem.pause();
            }
          }
          this.closeMiniAudio();
        });
      }
    },
    // 点击视频关闭其他
    closeVideo() {
      let allVideo = (
        this.container ? this.container : document
      ).querySelectorAll(".video");
      for (let index = 0; index < allVideo.length; index++) {
        const item = allVideo[index];
        item.addEventListener("playing", (item) => {
          const path = item.srcElement.src;
          const videoList = Array.from(allVideo);
          for (let cindex = 0; cindex < videoList.length; cindex++) {
            const citem = videoList[cindex];
            if (citem.currentSrc != path && path) {
              citem.pause();
            }
          }
        });
      }
    },
    // 视频小窗
    handleVideoPicture() {
      let doms = (this.container ? this.container : document).querySelectorAll(
        ".video"
      );
      doms = Array.from(doms);
      if (!doms.length) return false;
      const playVudio = doms.reverse().find((item) => item.paused == false);
      if (playVudio) {
        const bottomGap = playVudio.getBoundingClientRect().bottom;
        const topGap = playVudio.getBoundingClientRect().top;
        if (bottomGap < 0 || topGap > window.innerHeight) {
          try {
            if (playVudio.readyState) playVudio.requestPictureInPicture();
          } catch (error) {
            console.log(error, "小窗错误error");
          }
        }
      }
    },
    //其他类名下字体大小变化
    transformDom(fs) {
      if (!fs) return;
      let doms = (this.container ? this.container : document).querySelectorAll(
        ".block"
      );
      if (!doms.length) return;
      for (let index = 0; index < doms.length; index++) {
        const dom = doms[index];
        dom.style.fontSize = fs + "px";
      }
    },
  },
  components: {
    pageHeader,
    chapterOne,
    chapterTwo,
    chapterThree,
    chapterFour,
    chapterFive,
    chapterSix,
    chapterSeven,
  },
};
</script>
<style lang="less" scoped>
.page-main {
    width: 100% !important;
    height: 100% !important;
    overflow: auto;
  width: 100% !important;
  height: 100% !important;
  overflow: auto;
    .page-content {
        max-width: 816px;
        min-width: 375px;
        margin: 0 auto;
        padding-bottom: 100px;
    }
  .page-content {
    max-width: 816px;
    min-width: 375px;
    margin: 0 auto;
    padding-bottom: 100px;
  }
}
</style>