欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue 富文本编辑器动态大纲与演示模式(vue-quill-editor)

程序员文章站 2022-06-24 17:43:45
效果图编辑模式演示模式...

效果图

编辑模式

vue 富文本编辑器动态大纲与演示模式(vue-quill-editor)

演示模式

vue 富文本编辑器动态大纲与演示模式(vue-quill-editor)

废话不多说,下面直接开始上代码

// 相关依赖包
// 富文本编辑器
npm install vue-quill-editor –save
// 全屏依赖
npm install --save screenfull

编辑模式代码

自定义编辑器组件代码
<template>
  <div class="baseDiv">
    <div class="editor" ref="editor" :style="styles"></div>
    <div class="rightMenu" v-if="rightMenuShow">
      <div class="lake-sidebar-title">
        <span>大纲</span>
        <button
          @click="sidebarClick"
          style="line-height: 0; top: 0px"
          type="button"
          aria-label="Close"
          class="el-dialog__headerbtn"
        >
          <i class="el-dialog__close el-icon el-icon-close"></i>
        </button>
      </div>
      <div
        class="lake-sidebar-content lake-scrollable scroll-y"
        style="position: relative"
      >
        <div class="lake-synopsis">
          <div class="larkui-synopsis-wrap">
            <ul class="larkui-synopsis">
              <li
                class="larkui-synopsis-item larkui-synopsis-item-active"
                v-for="(item, i) in outlineList"
              >
                <span
                  class="larkui-synopsis-item-link larkui-synopsis-item-link-1"
                  :class="
                    item.tagName == 'H3'
                      ? 'h3Padding'
                      : item.tagName == 'H4'
                      ? 'h4Padding'
                      : ''
                  "
                >
                  <a :href="item.id" :title="item.title">
                    <span>{{ item.title }}</span>
                  </a>
                </span>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
// 富文本组件
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";

export default {
  name: "Editors",
  props: {
    /* 编辑器的内容 */
    value: {
      type: String,
      default: "",
    },
    /* 高度 */
    height: {
      type: Number,
      default: null,
    },
    outline: {
      type: String,
      default: ""
    }
  },
  data() {
    const that = this;
    return {
      readOnly: false,
      rightMenuShow: true,
      Quill: null,
      currentValue: "",
      options: {
        theme: "snow",
        bounds: document.body,
        debug: "warn",
        modules: {
          // 工具栏配置
          toolbar: {
            container: [
              ["bold", "italic", "underline", "strike"], // 加粗 斜体 下划线 删除线
              ["blockquote", "code-block"], // 引用  代码块
              [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
              [{ indent: "-1" }, { indent: "+1" }], // 缩进
              [{ size: [false, "small", "large", "huge"] }], // 字体大小
              [{ header: [false, 1, 2, 3, 4] }], // 标题
              [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
              [{ align: [] }], // 对齐方式
              ["clean"], // 清除文本格式
              ["link", "image", "video"], // 链接、图片、视频
              ["sidebar"],
            ],
            handlers: {
              shadeBox: null,
              sidebar: function () {
                that.rightMenuShow = !that.rightMenuShow;
              },
            },
          },
        },
        placeholder: "            请输入标题",
      },
      outlineList: [],
    };
  },
  computed: {
    styles() {
      let style = {};
      if (this.height) {
        style.height = `${this.height}px`;
      }
      style.width = "50%";
      style.margin = "0 0 0 25%";
      style.height = "calc(100% - 42px)";
      return style;
    },
  },
  watch: {
    value: {
      handler(val) {
        if (val !== this.currentValue) {
          this.currentValue = val === null ? "" : val;
          if (this.Quill) {
            this.Quill.pasteHTML(this.currentValue);
            console.log(this.currentValue);
          }
        }
      },
      immediate: true,
    },
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.Quill = null;
  },
  methods: {
    init() {
      this.outlineList = JSON.parse(this.outline);
      const editor = this.$refs.editor;
      this.Quill = new Quill(editor, this.options);
      this.Quill.pasteHTML(this.currentValue);
      this.parsingHtml(this.$refs.editor.children[0].innerHTML);
      this.Quill.on("text-change", (delta, oldDelta, source) => {
        const html = this.$refs.editor.children[0].innerHTML;
        const text = this.Quill.getText();
        const quill = this.Quill;
        this.currentValue = html;
        this.$emit("input", html);
        this.$emit("on-change", { html, text, quill});
        this.parsingHtml(html);
      });
      this.Quill.on("text-change", (delta, oldDelta, source) => {
        this.$emit("on-text-change", delta, oldDelta, source);
      });
      this.Quill.on("selection-change", (range, oldRange, source) => {
        this.$emit("on-selection-change", range, oldRange, source);
      });
      this.Quill.on("editor-change", (eventName, ...args) => {
        this.$emit("on-editor-change", eventName, ...args);
      });

      const sourceEditorButton = document.querySelector(".ql-sidebar");
      sourceEditorButton.icon = 'el-icon-s-unfold';
      sourceEditorButton.style.cssText =
        "width:40px; border:1px solid #ccc; border-radius:5px;";
      sourceEditorButton.innerText = "大纲";
    },
    sidebarClick() {
      this.rightMenuShow = !this.rightMenuShow;
    },
    parsingHtml(html) {
      const el = document.createElement("div");
      const that = this;
      el.innerHTML = html;
      let hList = [];
      that.outlineList = [];
      let index = 0;
      let bol = true;
      // 遍历所有html标签,寻找h标签作为大纲
      el.querySelectorAll("*").forEach((item) => {
        if (
          item.tagName == "H2" ||
          item.tagName == "H3" ||
          item.tagName == "H4"
        ) {
          index ++;
          that.outlineList.push({
            title: item.innerText,
            tagName: item.tagName,
            id: '#' + item.tagName + index
          });
        }
      });
      that.$emit("getOutlineList", that.outlineList);
      // 为富文本中的内容增加id属性,锚点使用
      index = 0;
      document.getElementsByClassName('ql-editor')[0].childNodes.forEach((item) => {
        if (item.innerText && bol) {
          this.$emit("title", item.innerText);
          bol = false;
        }
        if (
          item.tagName == "H2" ||
          item.tagName == "H3" ||
          item.tagName == "H4"
        ) {
          index++;
          item.id = item.tagName + index;
        }
      })
    },
  },
};
</script>
<style type="scss">
html,body{height:100%;overflow: hidden;}
#app,.baseDiv{height: 100%;}
</style>
<style>
.editor,
.ql-toolbar {
  white-space: pre-wrap !important;
  line-height: normal !important;
}
.quill-img {
  display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
  content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0px;
  content: "保存";
  padding-right: 0px;
}

.ql-snow .ql-tooltip[data-mode="video"]::before {
  content: "请输入视频地址:";
}

.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: "14px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
  content: "10px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
  content: "18px";
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
  content: "32px";
}

.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: "正文";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
  content: "标题1";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
  content: "标题2";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
  content: "标题3";
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
  content: "标题4";
}
/* .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
  content: "标题5";
} */
/* .ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
  content: "标题6";
} */

.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: "标准字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
  content: "衬线字体";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
  content: "等宽字体";
}

.editor {
  float: left;
  overflow-y: hidden;
}
.rightMenu {
  float: left;
  width: 22%;
  margin: 20px 0 0 20px;
}

.lake-sidebar-title {
  position: relative;
  margin-bottom: 10px;
  font-size: 14px;
  font-weight: bold;
  padding: 0 2px 10px;
  border-bottom: 1px solid #e8e8e8;
}

.lake-toc-sidebar .lake-sidebar-content {
  overflow: auto;
  height: calc(100vh - 164px);
  margin-left: -60px;
  padding: 0 2px;
  box-sizing: border-box;
}

.larkui-synopsis-wrap {
  overflow: hidden;
}
.larkui-synopsis {
  width: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  font-size: 12px;
  list-style: none;
  padding: 0;
  margin: 0;
  display: block;
}
.larkui-synopsis .larkui-synopsis-item {
  line-height: 24px;
  color: #595959;
  display: list-item;
  text-align: -webkit-match-parent;
}

.larkui-synopsis .larkui-synopsis-item-link-1 {
  padding-left: 0;
}

.larkui-synopsis .larkui-synopsis-item-link {
  margin: 0 10px 0 0;
  width: calc(100% - 28px);
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

li {
  text-align: -webkit-match-parent;
}

.larkui-synopsis .larkui-synopsis-item-active a:link {
  color: black;
  text-decoration:none;
}

.larkui-synopsis .larkui-synopsis-item-active a:visited {
  color: black;
  text-decoration:none;
}

.larkui-synopsis .larkui-synopsis-item-active a:active {
  color: #25b864;
  text-decoration:none;
}

.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
  padding-left: 0px !important;
}

.title {
  font-size: 36px !important;
  color: #262626;
}

.h4Padding {
  padding-left: 2.4em !important;
}
.h3Padding {
  padding-left: 1.2em !important;
}
.ql-toolbar.ql-snow {
  width: 100%;
  background-color: #FCFCFC !important;
  z-index: 999999;
  text-align: center;
}
body {
  margin: 0;
}

.baseDiv {
  background-color: #F9F9F9;
}

.ql-editor {
  padding: 32px 60px 0 60px;
  background-color: white;
  min-height: 700px;
  overflow-y: auto;
}
/** 滚动条样式重写 */
.ql-editor::-webkit-scrollbar {
    width: 5px;
    height: 1px;
  }
.ql-editor::-webkit-scrollbar-thumb {
  border-radius: 10px;
  -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
  background:#7D7D7D;
}
.ql-editor::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 5px rgba(0,0,0,0.2);
  border-radius: 10px;
  background: #EDEDED;
}

</style>

编辑页面(自定义组件引入)
<template>
  <!-- 富文本组件的html内容有修改会自己传到value变量,大纲会通过getOutlineList传到outline中,所以你只需要写个保存事件将(value与outline还有title)入库做回显就可以了 -->
  <test v-model="value" :outline="outline"  @getOutlineList="getOutlineList" @title="getTitle"/>
</template>
<script>
// test即为自己定义的编辑器组件,这里引入使用
import test from  '@/components/test';
export default {
  data(){
    return {
      // 富文本HTML内容
      value: '<h1>这是标题</h1><p>	部分内容部分内容</p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	部分内容部分内容</p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	部分内容部分内容</p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><p>	部分内容部分内容</p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	部分内容部分内容</p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>	<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><h2 id="H21">	大纲一</h2><p>			部分内容部分内容</p><p>			部分内容部分内容</p><p>			<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>			<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>			部分内容部分内容</p><p>			<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>			<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><h3 id="H32"><span style="background-color: rgb(255, 255, 255);">      大纲三</span></h3><h2 id="H23">大纲二</h2><p>         啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊<span style="background-color: rgb(255, 255, 255);">啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊</span></p><p><br></p><p><br></p><h4 id="H44"><span style="background-color: rgb(255, 255, 255);">大纲四</span></h4><p><br></p>',
      // 大纲内容
      outline: '[{"title":"这是一个标题,同时它也是一个大纲","tagName":"H2","id":"#H21"},{"title":"这是第二个大纲","tagName":"H2","id":"#H22"},{"title":"","tagName":"H3","id":"#H33"},{"title":"这是一个子大纲","tagName":"H3","id":"#H34"},{"title":"","tagName":"H3","id":"#H35"},{"title":"这是子大纲的子大纲","tagName":"H4","id":"#H46"},{"title":"这是最后的大纲","tagName":"H2","id":"#H27"},{"title":"","tagName":"H3","id":"#H38"},{"title":"这是最后的子大纲","tagName":"H3","id":"#H39"}]',
      // 富文本中HTML的标题,即富文本中第一个标签的内容
      title: '',
    }
  },
  components: {
    test
  },
  methods: {
    getOutlineList(val) {
      this.outline = JSON.stringify(val);
      console.log('大纲内容=======================>>');
      console.log(this.outline);
      console.log('html内容=======================>>');
      console.log(this.value);
    },
    getTitle(val) {
      this.title = val;
      console.log('标题内容=======================>>');
      console.log(this.title);
    }
  }
}
</script>

演示模式
<template>
  <div class="isWin">
    <div class="main-wrapper">
      <div class="doc-head">
        <div class="Present-module_header_QR27a">
          <div class="CrumbView-module_wrapper_112MY">
            <span class="CrumbView-module_item_2s3Yw"> {{ title }} </span>
            <span class="CrumbView-module_item_2s3Yw"> {{ outlineText }} </span>
          </div>
          <div class="Present-module_actions_1f0CX">
            <a title="大纲" class="el-icon-s-unfold" @click="outlineShow" />
            <a title="全屏" class="el-icon-full-screen" @click="viewClick" />
          </div>
        </div>
      </div>

      <div class="doc-presenter">
        <article class="doc-article">
          <div class="doc-article-content" v-html="content"></div>
          <div class="OutlineView-module_wrapper_3YooJ" v-show="outlineVisible">
            <div class="OutlineView-module_header_1aWcC">
              <h3>大纲</h3>
              <span
                @click="outlineShow"
                class="OutlineView-module_closeBtn_Bfdq9 el-icon-close"
              ></span>
            </div>
            <div>
              <div
                class="OutlineView-module_item_3HZqe"
                :class="
                  item.tagName == 'H3'
                    ? 'h3Padding'
                    : item.tagName == 'H4'
                    ? 'h4Padding'
                    : ''
                "
                v-for="(item, i) in outlineList"
              >
                <a @click="outlineClick(item.id)" :title="item.title">
                  <span>{{ item.title }}</span>
                </a>
              </div>
            </div>
          </div>
        </article>
      </div>
    </div>
  </div>
</template>
<script>
// 下面这个这是全屏组件
import screenfull from "screenfull";
export default {
  name: "reportView",
  data() {
    return {
      outlineVisible: false,
      reportInfo: {},
      outlineList: [],
      content: null,
      title: "",
      outlineText: "",
    };
  },
  created() {
    this.init();
  },
  methods: {
    // 大纲显示隐藏
    outlineShow() {
      this.outlineVisible = !this.outlineVisible;
    },
    // 全屏
    viewClick() {
      screenfull.toggle();
    },
    init() {
      // 内容
      // 我的演示模式是跳转页面,数据直接存在了缓存里,下面提供一个存的例子,只需要拿到编辑模式里保存的数据往里面存就好
      const moke = {
        content:
          '<h1>这是标题</h1><p>\t部分内容部分内容</p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t部分内容部分内容</p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t部分内容部分内容</p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><p>\t部分内容部分内容</p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t部分内容部分内容</p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><h2 id="H21">\t大纲一</h2><p>\t\t\t部分内容部分内容</p><p>\t\t\t部分内容部分内容</p><p>\t\t\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t\t\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t\t\t部分内容部分内容</p><p>\t\t\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p>\t\t\t<span style="background-color: rgb(255, 255, 255);">部分内容部分内容</span></p><p><br></p><h3 id="H32"><span style="background-color: rgb(255, 255, 255);">      大纲三</span></h3><h2 id="H23">大纲二</h2><p>         啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊<span style="background-color: rgb(255, 255, 255);">啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊aaaaaaaaaaaaaa啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊</span></p><p><br></p><p><br></p><h4 id="H44"><span style="background-color: rgb(255, 255, 255);">大纲四</span></h4><p><br></p>',
        title: "这是标题",
        outline:
          '[{"title":"\\t大纲一","tagName":"H2","id":"#H21"},{"title":"      大纲三","tagName":"H3","id":"#H32"},{"title":"大纲二","tagName":"H2","id":"#H23"},{"title":"大纲四","tagName":"H4","id":"#H44"}]',
      };
      window.localStorage.setItem("reportInfo",JSON.stringify(moke));
      let reportInfo = window.localStorage.getItem("reportInfo");
      if (reportInfo) {
        reportInfo = JSON.parse(reportInfo);
        // 大纲
        this.outlineList = JSON.parse(reportInfo.outline);
        // 内容
        this.content = reportInfo.content;
        // 标题
        this.title = reportInfo.title;
      }
    },
    outlineClick(data) {
      // 这里因为直接使用a标签的href跳转锚点高度算不对,所以直接自己做了个计算
      const id = data.replace("#", "");
      const el = document.getElementById(id);
      window.scrollTo(0, el.offsetTop - 70);
      this.outlineText = el.innerText;
    },
  },
};
</script>
<style>
.main-wrapper {
  width: 100%;
  background: #fafafa;
}
.doc-head {
  -webkit-transition: none;
  transition: none;
}
.Present-module_header_QR27a {
  position: fixed;
  width: 100%;
  height: 60px;
  background: hsla(0, 0%, 100%, 0.96);
  -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.08);
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.08);
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
  z-index: 999;
  padding-left: 24px;
  padding-right: 24px;
}
.Present-module_actions_1f0CX,
.Present-module_header_QR27a {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  margin-right: 50px;
}
.CrumbView-module_wrapper_112MY {
  font-size: 18px;
}
.CrumbView-module_item_2s3Yw {
  font-weight: 500;
  color: #8c8c8c;
}
.CrumbView-module_item_2s3Yw:last-child {
  color: #262626;
}
.CrumbView-module_item_2s3Yw:after {
  content: "/";
  display: inline-block;
  margin-left: 0.5em;
  margin-right: 0.5em;
  font-weight: 400;
}
.CrumbView-module_item_2s3Yw:last-child:after {
  content: "";
}
[class^="el-icon-"],
[class*=" el-icon-"] {
  font-size: 1.5em;
}
.Present-module_actions_1f0CX a {
  margin-right: 15px;
}
.doc-presenter .doc-article {
  background: #fff;
  min-height: 680px;
  width: auto;
  margin: 0 auto;
  padding: 1px 10vw 6vw;
  -webkit-transition: width 0.3s linear, padding 0.3s linear;
  transition: width 0.3s linear, padding 0.3s linear;
  letter-spacing: 0.05em;
}
.OutlineView-module_wrapper_3YooJ {
  position: fixed;
  right: 0;
  top: 60px;
  padding: 0 32px 32px;
  width: 300px;
  height: calc(100vh - 60px);
  overflow: auto;
  -webkit-box-shadow: -2px 0 6px 0 rgba(0, 0, 0, 0.04);
  box-shadow: -2px 0 6px 0 rgba(0, 0, 0, 0.04);
  z-index: 99;
  background: #fff;
}
.OutlineView-module_header_1aWcC {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
  height: 64px;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  border-bottom: 1px solid #e8e8e8;
  font-size: 20px;
}
.OutlineView-module_closeBtn_Bfdq9 {
  background: none;
  border: none;
  font-size: 14px;
  cursor: pointer;
}
button {
  text-transform: none;
  overflow: visible;
  margin: 0;
  color: inherit;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  touch-action: manipulation;
  box-sizing: border-box;
  appearance: button;
  -webkit-writing-mode: horizontal-tb !important;
  text-rendering: auto;
  color: -internal-light-dark(black, white);
  letter-spacing: normal;
  word-spacing: normal;
  text-transform: none;
  text-indent: 0px;
  text-shadow: none;
  display: inline-block;
  text-align: center;
  align-items: flex-start;
  cursor: default;
  background-color: -internal-light-dark(rgb(239, 239, 239), rgb(59, 59, 59));
  box-sizing: border-box;
  margin: 0em;
  font: 400 13.3333px Arial;
  padding: 1px 6px;
  border-width: 2px;
  border-style: outset;
  border-color: -internal-light-dark(rgb(118, 118, 118), rgb(133, 133, 133));
  border-image: initial;
}
.anticon {
  display: inline-block;
  color: inherit;
  font-style: normal;
  line-height: 0;
  text-align: center;
  text-transform: none;
  vertical-align: -0.125em;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
/* .OutlineView-module_item_3HZqe.active {
  color: #096dd9;
  font-weight: 500;
} */
.OutlineView-module_item_3HZqe {
  font-size: 18px;
  margin-top: 12px;
  cursor: pointer;
}
.OutlineView-module_header_1aWcC h3 {
  margin-top: 0;
  margin-bottom: 0.5em;
  color: #262626;
  font-weight: 500;
  display: block;
  font-size: 1.17em;
  margin-block-start: 1em;
  margin-block-end: 1em;
  margin-inline-start: 0px;
  margin-inline-end: 0px;
  font-weight: bold;
}

.h4Padding {
  padding-left: 2.4em !important;
}
.h3Padding {
  padding-left: 1.2em !important;
}

.doc-article-content {
  margin-top: 70px;
}

img {
  width: 100%;
}

body {
  margin: 0px;
}
</style>

ps:样式确实写得很烂,不要吐槽我。。。。。

本文地址:https://blog.csdn.net/qq_38101240/article/details/111869826

相关标签: vue elementui js