vu3项目使用 v-md-editor 生成文章目录(点击跳转、滚动高亮)

怎么安装v-md-editor编辑器以及使用不是这篇文章的内容,以下内容主要是v-md-editor编辑器的预览组件生成内容生成目录 实现点击标题跳转、滚动页面标题高亮方法

如何使用这个编辑器

请查看官网文档:https://code-farmer-i.github.io/vue-markdown-editor/

正文开始

  • 直接撸代码
<v-md-preview :text="articleData.content"  ref="preview"></v-md-preview>

 <ul class="directory-content">
      <li class="directory-item" v-for="(anchor, index) in titles" :key="anchor.title"
         :class="currentIndex === index ? 'active' : ''" :style="{ paddingLeft: `${5 + anchor.indent * 15}px` }"
               @click="handleAnchorClick(anchor, index)" >
         <a>{{ anchor.title }}</a>
    </li>
</ul>
import {ref, onMounted, onUnmountedh,nextTick} from 'vue';

const preview = ref(null);
const titles = ref([]);
const currentIndex = ref(0);

const getMarkdownTitles = async () => {
  await nextTick();

  const anchors = preview.value.$el.querySelectorAll("h1,h2,h3,h4,h5,h6");
  const titles = Array.from(anchors).filter((title) => !!title.innerText.trim());

  if (!titles.length) {
    return [];
  }

  const hTags = Array.from(new Set(titles.map((title) => title.tagName))).sort();
  return titles.map((el) => ({
    title: el.innerText,
    lineIndex: el.getAttribute("data-v-md-line"),
    indent: hTags.indexOf(el.tagName),
  }));
  
};

// 在需要的位置直接调用生成目录
const fetchMarkdownTitles = async () => {
  titles.value = await getMarkdownTitles();
};


onMounted(() => {
   //这里请按照自己的页面的元素来修改
  const scrollContainer = document.querySelector('.wrz_blog-reader-container');
  if (scrollContainer){
    scrollContainer.addEventListener('scroll', readerScroll);
  }
});

onUnmounted(() => {
//这里请按照自己的页面的元素来修改
  const scrollContainer = document.querySelector('.wrz_blog-reader-container');
  if (scrollContainer) {
    scrollContainer.removeEventListener('scroll', handleScroll);
  }
});

const readerScroll = () => {
  const headings = preview.value.$el.querySelectorAll("h1,h2,h3,h4,h5,h6");

  // 找到当前在视图中的标题
  let currentHeading = null;
  for (let i = 0; i < headings.length; i++) {
    const heading = headings[i];
    const rect = heading.getBoundingClientRect();
    const scrollContainer = document.querySelector('.wrz_blog-reader-container');
    // 判断标题元素中心是否在视图中
    if (rect.top <= scrollContainer.clientHeight / 2 && rect.bottom >= 0) {
      currentHeading = heading;
      break;
    }
  }

  // 根据当前标题更新 currentIndex
  if (currentHeading) {
    const lineIndex = currentHeading.getAttribute("data-v-md-line");
    const index = titles.value.findIndex((anchor) => anchor.lineIndex === lineIndex);

    if (index !== -1 && currentIndex.value !== index) {
      currentIndex.value = index;
      updateActiveClass();
    }
  }
};


// 添加用于更新 active 类的函数
const updateActiveClass = () => {
  //修改成你自己的元素
  const titlesElements = document.querySelectorAll('.directory-item');
  titlesElements.forEach((title, index) => {
    title.classList.toggle('active', currentIndex.value === index);
  });
};

const handleAnchorClick = async (anchor, idx) => {
  await nextTick();
  const heading = preview.value.$el.querySelector(`[data-v-md-line="${anchor.lineIndex}"]`);
  //修改成你自己的元素
  const scrollContainer = document.querySelector('.wrz_blog-reader-container');
  if (heading) {
    scrollContainer.scrollTo({
      top: heading.offsetTop,
      behavior: 'smooth',
    });

    // 更新currentIndex
    currentIndex.value = idx;
    updateActiveClass();
  }
};

效果展示

在这里插入图片描述

请关注我的博客

王润泽
https://wangrunze.com/

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值