开箱即用的文档导读功能

安装 npm i @kangc/v-md-editor -S@1.7.11

将需要展示的内容赋值给 markdown 变量即可

<template>
  <div class="v-md-editor-container">
    <div class="v-md-editor-nav">
      <ul>
        <li v-for="(heading, index) in headings" :key="index" @click="handleNavClick(index)">{{ heading.textContent }}
        </li>
      </ul>
    </div>
    <div class="v-md-editor-wrapper">
      <v-md-preview ref="editor" :text="markdown" @scroll="$refs.previewContainer.scrollTop = $event.target.scrollTop" />
    </div>
  </div>
</template>

<script>
import Vue from "vue";;
import vuepressTheme from "@kangc/v-md-editor/lib/theme/vuepress.js";
import "@kangc/v-md-editor/lib/theme/style/vuepress.css";
import VMdPreview from "@kangc/v-md-editor/lib/preview";
VMdPreview.use(vuepressTheme, {});
Vue.use(VMdPreview);
export default {
  data() {
    return {
      markdown: '',
      headings: [],
    };
  },
  mounted() {
    // 监听滚动事件
    this.$refs.editor.$el.addEventListener('scroll', this.handleScroll);
    // 初始化所有的 Markdown Titles
    this.initHeadings();
  },
  beforeDestroy() {
    // 销毁组件时取消监听滚动事件
    this.$refs.editor.$el.removeEventListener('scroll', this.handleScroll);
  },
  methods: {
    // 获取markdown preview中的所有h1~h6元素
    initHeadings() {
      const previewContainer = this.$refs.editor.$el;
      this.headings = previewContainer.querySelectorAll('h1, h2, h3, h4, h5, h6');
    },
    // 处理导航栏点击事件
    handleNavClick(index) {
      // 获取对应元素
      const targetElement = this.headings[index];
      // 将目标元素滚动到视图顶部
      targetElement.scrollIntoView({ behavior: 'smooth' });
      // 设置高亮样式
      this.setActiveNav(index);
    },
    // 监听滚动事件并处理高亮逻辑
    handleScroll(e) {
      const scrollTop = e.target.scrollTop;

      // 遍历所有markdown preview中的h1~h6元素,确定高亮元素
      let activeIndex = -1;
      for (let i = 0; i < this.headings.length; i++) {
        const element = this.headings[i];
        if (element.offsetTop <= scrollTop) {
          activeIndex = i;
        } else {
          break;
        }
      }

      // 更新高亮样式
      this.setActiveNav(activeIndex);
    },
    // 更新导航栏的高亮样式
    setActiveNav(index) {
      // 先移除之前选中的样式
      const prevActiveItem = this.$el.querySelector('.active');
      if (prevActiveItem) {
        prevActiveItem.classList.remove('active');
      }

      // 再为目标元素添加选中样式
      const currentItem = this.$el.querySelectorAll('.v-md-editor-nav li')[index];
      if (currentItem) {
        currentItem.classList.add('active');
      }
    },
  },
};
</script>

<style>
.v-md-editor-container {
  display: flex;
  height: 100%;
}

.v-md-editor-nav {
  width: 200px;
  border-right: 1px solid rgba(0, 0, 0, 0.1);
  height: 100%;
  overflow-y: scroll;
}

.v-md-editor-nav ul {
  margin: 0;
  padding: 20px;
}

.v-md-editor-nav li {
  list-style: none;
  font-size: 14px;
  line-height: 24px;
  cursor: pointer;
  transition: background-color 0.2s ease-in-out;
}

.v-md-editor-nav li:hover {
  background-color: #f5f5f5;
}

.v-md-editor-nav li.active {
  background-color: #e9e9e9;
  font-weight: bold;
}

.v-md-editor-wrapper {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.v-md-editor-preview {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.v-md-editor-preview h1 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 2em;
}

.v-md-editor-preview h2 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 1.5em;
}

.v-md-editor-preview h3 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 1.17em;
}

.v-md-editor-preview h4 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 1em;
}

.v-md-editor-preview h5 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 0.83em;
}

.v-md-editor-preview h6 {
  margin-top: 1.5em;
  margin-bottom: 0.5em;
  font-size: 0.67em;
}

.v-md-editor-preview p {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  line-height: 1.75em;
  color: rgba(0, 0, 0, 0.87);
}

.v-md-editor-preview ol,
.v-md-editor-preview ul {
  margin-top: 1.5em;
  margin-bottom: 1.5em;
  margin-left: 2em;
  padding: 0;
  list-style-position: outside;
  line-height: 1.75em;
}

.v-md-editor-preview li {
  margin-bottom: 0.5em;
  line-height: 1.75em;
  color: rgba(0, 0, 0, 0.87);
}

.v-md-editor-preview code {
  background-color: #f5f5f5;
  padding: 0.1em 0.3em;
  border-radius: 0.2em;
  font-size: 85%;
}

.v-md-editor-preview pre {
  margin: 1.5em 0;
  font-size: 14px;
  font-family: Consolas, Menlo, monospace;
  background-color: #f5f5f5;
  border-radius: 6px;
  padding: 10px 20px;
  overflow: auto;
}
</style>

例子

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值