@@ -3,6 +3,7 @@ import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
33import type { CSSProperties } from ' vue'
44import {
55 useSlotsExist ,
6+ useMutationObserver ,
67 useEventListener ,
78 useResizeObserver ,
89 rafTimeout ,
@@ -55,6 +56,7 @@ const initialDisplay = ref<boolean>(false) // 性能优化,使用 v-if 避免
5556const tooltipShow = ref <boolean >(false ) // tooltip 显示隐藏标识
5657const tooltipTimer = ref () // tooltip 延迟显示隐藏的定时器标识符
5758const scrollTarget = ref <HTMLElement | null >(null ) // 最近的可滚动父元素
59+ const scrollTop = ref <number >(0 ) // scrollTarget 的滚动位置
5860const cardTop = ref <number >(0 ) // 弹出框相对于 tooltipContent 的垂直位置
5961const cardLeft = ref <number >(0 ) // 弹出框相对于 tooltipContent 的水平位置
6062const tooltipPlace = ref <' top' | ' bottom' | ' left' | ' right' >(' top' ) // 弹出框位置
@@ -160,6 +162,17 @@ onMounted(() => {
160162onBeforeUnmount (() => {
161163 cleanup ()
162164})
165+ // 监听 vitepress 文档页面滚动
166+ const mutationObserver = useMutationObserver (
167+ scrollTarget ,
168+ () => {
169+ if (scrollTop .value !== scrollTarget .value ?.scrollTop ) {
170+ scrollTop .value = scrollTarget .value ?.scrollTop ?? 0
171+ updatePosition ()
172+ }
173+ },
174+ { subtree: true , attributes: true }
175+ )
163176useEventListener (window , ' resize' , getViewportSize )
164177// 监听 tooltipCard 和 tooltipContent 的尺寸变化,更新弹出框位置
165178useResizeObserver ([tooltipCardRef , tooltipContentRef ], (entries : ResizeObserverEntry []) => {
@@ -208,7 +221,17 @@ function observeScroll() {
208221 updatePosition ,
209222 passiveSupported .value ? { passive: true } : undefined
210223 )
224+ if (scrollTarget .value === document .documentElement ) {
225+ mutationObserver .start ()
226+ } else {
227+ mutationObserver .stop ()
228+ }
211229}
230+ /**
231+ * 清理滚动监听事件并重置滚动目标。
232+ *
233+ * 清理函数,移除滚动事件监听并重置滚动目标
234+ */
212235function cleanup() {
213236 scrollTarget .value && scrollTarget .value .removeEventListener (' scroll' , updatePosition )
214237 scrollTarget .value = null
@@ -265,7 +288,13 @@ async function getPosition() {
265288// 获取可滚动父元素或视口的矩形信息
266289function getShelterRect() {
267290 if (scrollTarget .value ) {
268- return scrollTarget .value .getBoundingClientRect ()
291+ const scrollTargetRect = scrollTarget .value .getBoundingClientRect ()
292+ return {
293+ top: scrollTargetRect .top < 0 ? 0 : scrollTargetRect .top ,
294+ left: scrollTargetRect .left < 0 ? 0 : scrollTargetRect .left ,
295+ bottom: scrollTargetRect .bottom > viewportHeight .value ? viewportHeight .value : scrollTargetRect .bottom ,
296+ right: scrollTargetRect .right > viewportWidth .value ? viewportWidth .value : scrollTargetRect .right
297+ }
269298 }
270299 return {
271300 top: 0 ,
0 commit comments