跳转到内容

页面导航自动滚动 ​

其他模块函数:

实现代码:

ts
import { getScrollOffsetTop, throttleAndDebounce } from '../../utils/common'
import { onMounted, onUnmounted, ref } from 'vue'

// 底边距(底部阴影区域的高度)
const PADDING_BOTTOM = 32

// 获取 Aside 容器的内容区域高度
const getAsideContainerContentHeight = (el: HTMLElement) => {
  const paddingTop = parseInt(getComputedStyle(el).paddingTop)
  return el.clientHeight - paddingTop - PADDING_BOTTOM
}


export const useOutlineAutoScroll = (): void => {
  const asideContainerRef = ref<HTMLElement>()

  // 使用 throttleAndDebounce,保持和 vitepress 更新激活的 outline link 的行为一致,并减少计算开销
  const autoScroll = throttleAndDebounce(() => {
    if (!asideContainerRef.value) return

    // 获取当前激活的的 outline link
    const activeLink = asideContainerRef.value.querySelector<HTMLElement>(
      '.outline-link.active',
    )

    if (!activeLink) return

    // 滚动容器的内容区域高度
    const contentHeight = getAsideContainerContentHeight(
      asideContainerRef.value,
    )
    if (Number.isNaN(contentHeight)) return

    // 获取当前激活的 link 相对于滚动容器的顶部偏移
    const linkScrollOffsetTop = getScrollOffsetTop(
      activeLink,
      asideContainerRef.value,
    )
    if (Number.isNaN(linkScrollOffsetTop)) return

    const containerScrollTop = asideContainerRef.value.scrollTop
    const linkHeight = activeLink.offsetHeight

    if (linkScrollOffsetTop < containerScrollTop) {
      asideContainerRef.value.scrollTo({
        top: linkScrollOffsetTop,
        behavior: 'smooth',
      })
    } else if (
      linkScrollOffsetTop + linkHeight >
      containerScrollTop + contentHeight
    ) {
      asideContainerRef.value.scrollTo({
        top: linkScrollOffsetTop - contentHeight + linkHeight,
        behavior: 'smooth',
      })
    }
  }, 100)

  const handleScroll = (): void => {
    autoScroll()
  }

  onMounted(() => {
    // 滚动容器
    const el = document.querySelector<HTMLElement>(
      '.Layout .VPContent .aside .aside-container',
    )

    if (!el) return

    asideContainerRef.value = el

    window.addEventListener('scroll', handleScroll)
  })

  onUnmounted(() => {
    window.removeEventListener('scroll', handleScroll)
  })
}

标题1 ​

标题2 ​

标题3 ​

标题4 ​

标题5 ​

标题6 ​

标题7 ​

标题8 ​

标题9 ​

标题10 ​

标题11 ​

标题12 ​

标题13 ​

标题14 ​

标题15 ​

标题16 ​

标题17 ​

标题18 ​

标题19 ​

标题20 ​