实现文章目录转跳|青训营笔记

96 阅读1分钟

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

目录贴顶

遇到了获取元素的 offsetTop 的问题

(参考 blog.csdn.net/weixin_4870…

问题是获取到初始的boxTop值

  • created 肯定不行,压根通过 this.$refs 获取不到元素
  • mounted 也不行,数据还没有获取到
  • updated 也不行,获取到了数据 Dom 还没有渲染
  • $nextTick 也不行,因为 dom 渲染了但是图片还没有加载完毕
  • 在图片都加载完毕后获取元素的 offsetTop, 这里注意防抖函数的应用

普通 元素用的是 this.$refs.元素ref名.offsetTop

组件 用的是 this.refs.组件ref.refs.组件ref名.el.offsetTop

最后采用在挂载时使用setTimeout,做一个宏任务处理

let boxTop = ref(0);
let scrollTop = ref(0);
onMounted(() => {
  setTimeout(() => {
    boxTop.value = document.querySelector('.catalog-box').offsetTop;
  }, 0);
  window.addEventListener('scroll', () => {
    scrollTop.value = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    handleScroll();
  });
});

绑定样式isTop,通过监听滚动,来判断现在滚动到哪里。合并项目还有个header,所以+60。

<div id="catalog-main" :class="{ isTop: isTop }" ref="catalog">
let isTop = ref(false);
const handleScroll = () => {
  if (scrollTop.value >= boxTop.value + 60) {
    isTop.value = true;
  } else {
    isTop.value = false;
  }
};

bug发现!!!

页面刷新问题,刷新页面后不会回到顶部。鼠标下滚后刷新页面就会崩坏 boxTop.value 定死就不会了

目录显示与点击转跳

思路:

在文章内容组件获取数据时,通过数据查找h标签,把h1和h2的内容提取出来,传标签size,标签内容,标签id。

我决定用a标签锚点进行转跳,因为掘金官网看着是a标签转跳。

给原本筛选出来的h标签套一层div。

bug发现!!!

同等级同内容的h标签,转跳就会崩坏

直接在h标签上

这里采用"jump-xx"命名,直接追加上# 保存,这样目录组件使用更方便。

let tocs = articleContent.match(/<h[1-2].*?>.*?<\/h[1-2]>/g);
tocs.forEach((item, index) => {
    let _tocs = `<div id="jump-${index}">${item}</div>`;
    articleContent = articleContent.replace(item, _tocs);
});
let hData = tocs.map((item, index) => {
    let hContent = item.match(/<h(\d).*?>(.*?)<\/h[1-2]>/);
    const jump = `#jump-${index}`;
    return { id: hContent[1], content: hContent[2], jumpId: jump };
});

通过状态管理将数据保留

Nuxt.js | Pinia 中文文档 (web3doc.top)

使用pinia

npm install @pinia/nuxt

npm add -D pinia @pinia/nuxt @nuxtjs/composition-api

在 nuxt.config.js 中(这里暂时是nuxt项目,后期变为nuxt3,无需配置

    modules: [
        '@pinia/nuxt',
      ],

在 stores/hData.ts 中

import { defineStore } from 'pinia'

export const useHListStore = defineStore('hData', {
    state: () => {
        return {
            hList: []
        }
    }
})

在 [id].vue 中,将获取的数据放入

import { useHListStore } from "@/stores/hData"
//传给子组件 目录
const hListStore = useHListStore();
hListStore.$patch({hList: hData});

在目录组件中

<a :href="hItem.jumpId">{{ hItem.content }}</a>
import { useHListStore } from "@/stores/hData"
const hListStore = useHListStore();
const hList = hListStore.hList;