Skip to content

Commit 040f9d3

Browse files
feat: optimize tooltip flip
1 parent a95b3e0 commit 040f9d3

File tree

3 files changed

+35
-2
lines changed

3 files changed

+35
-2
lines changed

components/tooltip/Tooltip.vue

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ref, computed, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
33
import type { CSSProperties } from 'vue'
44
import {
55
useSlotsExist,
6+
useMutationObserver,
67
useEventListener,
78
useResizeObserver,
89
rafTimeout,
@@ -55,6 +56,7 @@ const initialDisplay = ref<boolean>(false) // 性能优化,使用 v-if 避免
5556
const tooltipShow = ref<boolean>(false) // tooltip 显示隐藏标识
5657
const tooltipTimer = ref() // tooltip 延迟显示隐藏的定时器标识符
5758
const scrollTarget = ref<HTMLElement | null>(null) // 最近的可滚动父元素
59+
const scrollTop = ref<number>(0) // scrollTarget 的滚动位置
5860
const cardTop = ref<number>(0) // 弹出框相对于 tooltipContent 的垂直位置
5961
const cardLeft = ref<number>(0) // 弹出框相对于 tooltipContent 的水平位置
6062
const tooltipPlace = ref<'top' | 'bottom' | 'left' | 'right'>('top') // 弹出框位置
@@ -160,6 +162,17 @@ onMounted(() => {
160162
onBeforeUnmount(() => {
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+
)
163176
useEventListener(window, 'resize', getViewportSize)
164177
// 监听 tooltipCard 和 tooltipContent 的尺寸变化,更新弹出框位置
165178
useResizeObserver([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+
*/
212235
function cleanup() {
213236
scrollTarget.value && scrollTarget.value.removeEventListener('scroll', updatePosition)
214237
scrollTarget.value = null
@@ -265,7 +288,13 @@ async function getPosition() {
265288
// 获取可滚动父元素或视口的矩形信息
266289
function 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,

docs/guide/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
对于新功能、新组件、`bug` 修复以及文档更新,您可以向 `main` 分支创建拉取请求或通过右下角邮箱地址联系我
66

7+
## <VersionDateTag date="2025-09-02">2.4.20</VersionDateTag>
8+
9+
- 优化并更新 [文字提示 Tooltip](https://themusecatcher.github.io/vue-amazing-ui/guide/components/tooltip.html) 组件,兼容弹出框在文档中自动调整弹出位置的功能
10+
711
## <VersionDateTag date="2025-08-28">2.4.19</VersionDateTag>
812

913
- 优化并更新 [选择器 Select](https://themusecatcher.github.io/vue-amazing-ui/guide/components/select.html) 组件,新增 `placement` `flip` `to` 属性,支持:设置下拉面板弹出位置;设置下拉面板被浏览器窗口或最近可滚动父元素遮挡时自动调整弹出位置;设置下拉面板挂载的容器节点,默认挂载到 `body`

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-amazing-ui",
3-
"version": "2.4.19",
3+
"version": "2.4.20",
44
"private": false,
55
"type": "module",
66
"author": "theMuseCatcher",

0 commit comments

Comments
 (0)