vitepress-theme-base-teek
Version:
查看 [使用说明](https://vp.xiaoying.org.cn/pages/9d746f)
71 lines (60 loc) • 1.88 kB
text/typescript
import { onMounted, onUnmounted, reactive, unref, watch } from "vue";
import { useData } from "vitepress";
export const useAnchorScroll = () => {
const { theme } = useData();
// 初始化当前锚点
const currentAnchor = reactive({
id: "",
top: -1,
});
/**
* 定义计算当前锚点的方法
*/
const calculateCurrentAnchor = () => {
// 获取页面中所有的锚点元素
const anchors = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
for (let i = 0; i < anchors.length; i++) {
const anchor = anchors[i];
// display 为 none 的元素不参与计算,跳过
const computedStyle = window.getComputedStyle(anchor);
if (computedStyle.display === "none") break;
const rect = anchor.getBoundingClientRect();
// 如果当前锚点距离顶部最近,且距离页面顶部小于等于 150,则将其设置为当前锚点
if (rect.top <= 150 && anchor.id !== currentAnchor.id) {
currentAnchor.id = anchor.id;
currentAnchor.top = rect.top;
}
}
};
/**
* 监听 window 对象的滚动事件
*/
const onScroll = () => {
calculateCurrentAnchor();
};
/**
* 在组件挂载时启动监听滚动事件
*/
onMounted(() => {
window.addEventListener("scroll", onScroll);
});
/**
* 在组件卸载时移除监听滚动事件
*/
onUnmounted(() => {
window.removeEventListener("scroll", onScroll);
});
/**
* 文档更新锚点的时候更新 url 中的 hash
*/
const startWatch = () => {
if (unref(theme).anchorScroll === false) return;
watch(
() => currentAnchor.id,
(val: string) => {
if (val) window.history.replaceState(history.state || null, "", `#${val}`);
}
);
};
return { startWatch };
};