文章导航 | 青训营笔记

59 阅读2分钟

这是我参与「第五届青训营」伴学笔记创作活动的第 10 天

呜呜呜

好难顶呜呜呜,应该是因为自己基础不够扎实,对于一些dom操作不熟悉,导致开发效率真的低,昨晚一个获取标题标签搞了两三小时,今晚一个attributes也搞我好久

真心bug很搞人心态,眼睛都累了

image.png

继上篇md字符串转html | 青训营笔记 - 掘金 (juejin.cn)把strapi项目拿到的md字符串转html之后,渲染在页面上,然后就想获取所有标题标签实现导航

类似掘金的这个

image.png

实现思路

最最重要的代码思路

<article class="article-content" v-html="htmls" id="articleContent"></article>

我是先获取element元素,然后,就是这里一句很关键,我试着打印,发现获取到的值是不一样的 image.png 这就一直导致我遍历node节点失败,一直报错,很惨 发现这个问题之后,我就利用settimeout,来“等一会”再执行遍历,这下终于就成功了

由于a标签瞄点功能对应的标签需要有name属性,所以用setAttribute把id给复制一份过去(marked插件渲染出来的标签自带id,id是innerText) 这样就获取所有满足tags数组里的标题数组,再利用组件通信把数组传出去,这里建议记得加.value image.png 再利用tags定义目标标题,h1~4,利用findIndex函数获取node节点有没有可以展示的,定义一个数组来存放 image.png

组件的调用就基本这样了 image.png

因为我把marked渲染html封装在组件中,所以在父组件中调用组件时要监听事件getNavTree 然后动态添加a标签,导航基本就实现了

image.png

这里添加的点击事件,是因为有一个顶部tab,但a标签的瞄点功能直接把那个标题顶到最上边,会被挡住的,所以我搜了好久好久,看了好多好多,才发现有这么个解决方法,我真的得回去重新好好学学js了,蠢哭了

重要代码

a.addEventListener("click", (e) => {
      window.scrollTo(0, 100);
      // console.log(e.target.innerText);
      let item = document.getElementById(e.target.innerText);
      console.log(item.offsetTop);
      setTimeout(() => {
        console.log("aaa");
        window.scrollTo({
          left: 0,
          top: item.offsetTop - 100,
          behavior: "smooth",
        });
      }, 200);

    });
watch(htmls, () => {
  let htmlNode = document.getElementsByTagName("article") || null;
  // 浏览器控制台展开console的时候会重新获取值
  setTimeout(() => {
    let iindex = -1;
    for (let i = 0; i < htmlNode[0].children.length; i++) {
      iindex = Tags.findIndex((item) => {
        return item == htmlNode[0].children[i].tagName;
      });
      htmlNode[0].children[i].setAttribute("name", htmlNode[0].children[i].id);
      if (iindex !== -1) {
        navTree.value.push({
          tagName: htmlNode[0].children[i].tagName,
          id: htmlNode[0].children[i].innerText,
          navIndex: iindex + 1,
        });
      }
    }
    emits("navigations", navTree.value);
  }, 3000);
});