Tooltip 文字组件


Tooltip 文字组件


导出的类型

1. TooltipProps

  • 描述: Tooltip 组件的 props 配置。
  • 字段:
    • content?: string
      提示框显示的内容文本。
    • trigger?: 'hover' | 'click' | 'contextmenu'
      触发方式(默认 'hover')。
    • placement?: Placement
      Popper.js 的定位策略(如 'bottom')。
    • manual?: boolean
      是否手动控制显示(默认 false)。
    • disabled?: boolean
      是否禁用组件(默认 false)。
    • popperOptions?: Partial<Options>
      Popper.js 的配置选项。
    • transition?: string
      过渡动画名称(默认 'fade')。
    • showTimeout?: number
      显示延迟(默认 0)。
    • hideTimeout?: number
      隐藏延迟(默认 200)。

2. TooltipEmits

  • 描述: Tooltip 组件的事件类型。
  • 字段:
    • 'visible-change': (value: boolean) => void
      提示框显示状态变化时触发。
    • 'click-outside': () => void
      点击外部区域时触发。

3. TooltipInstance

  • 描述: Tooltip 组件暴露给外部的接口。
  • 字段:
    • show(): 手动显示提示框。
    • hide(): 手动隐藏提示框。


关键代码解释

1. defineOptions

1
2
3
defineOptions({
name: 'VrTooltip',
});
  • 作用: 定义组件名称为 VrTooltip,在全局注册时可通过 <vr-tooltip> 使用。
  • 使用场景: 在 packages/core/components.ts 中通过以下方式导入并注册:
    1
    2
    import { VrTooltip } from '@veyra/components';
    export const components = [VrTooltip];

2. withDefaults 设置默认值

1
2
3
4
5
6
7
const props = withDefaults(defineProps<_TooltipProps>(), {
placement: 'bottom',
trigger: 'hover',
transition: 'fade',
showTimeout: 0,
hideTimeout: 200,
});
  • 示例:
    • placement 默认为 'bottom'
    • trigger 默认为 'hover'

3. 事件策略映射

1
2
3
4
5
6
7
const triggerStrategyMap: Map<string, () => void> = new Map();
triggerStrategyMap.set('hover', () => {
events.value['mouseenter'] = openFinal;
outerEvents.value['mouseleave'] = closeFinal;
dropdownEvents.value['mouseenter'] = openFinal;
});
// 其他策略类似
  • 作用: 根据 trigger 类型绑定不同事件(如 'hover' 绑定鼠标悬停事件)。

4. 防抖逻辑

1
2
3
4
watchEffect(() => {
openDebounce = debounce(bind(setVisible, null, true), openDelay.value);
closeDebounce = debounce(bind(setVisible, null, false), closeDelay.value);
});
  • 作用: 通过 debounce 实现显示和隐藏的延迟控制(如 showTimeouthideTimeout)。

5. Popper.js 集成

1
2
3
4
5
6
7
8
9
10
watch(visible, (val) => {
if (!val) return;
if (triggerNode.value && popperNode.value) {
popperInstance = createPopper(
triggerNode.value,
popperNode.value,
popperOptions.value
);
}
}, { flush: 'post' });
  • 作用: 根据 placementpopperOptions 动态定位提示框的位置。

6. 虚拟触发节点处理

1
2
3
4
5
6
7
8
9
10
const triggerNode = computed(() => {
if (props.virtualTriggering) {
return (
((props.virtualRef as ButtonInstance)?.ref as any) ??
(props.virtualRef as HTMLElement) ??
_triggerNode.value
);
}
return _triggerNode.value as HTMLElement;
});
  • 作用: 支持通过 virtualRef 绑定外部组件(如按钮)作为触发器,而非直接渲染的节点。

7. 事件监听与清理

1
2
3
onUnmounted(() => {
destroyPopperInstance();
});
  • 作用: 在组件卸载时销毁 Popper 实例并清理事件监听器,避免内存泄漏。

8. 自定义钩子 useEventsToTiggerNode

1
2
3
4
5
6
7
8
export function useEvenstToTiggerNode(
props: TooltipProps & { virtualTriggering?: boolean },
triggerNode: ComputedRef<HTMLElement | undefined>,
events: Ref<Record<string, EventListener>>,
closeMethod: () => void
) {
// 内部实现绑定/解绑事件到虚拟触发节点
}
  • 作用: 当 virtualTriggeringtrue 时,将事件绑定到外部提供的虚拟触发节点(如按钮组件的 ref)。

9. 模板中的动态渲染

1
2
3
4
5
6
<template v-if="!virtualTriggering">
<div class="vr-tooltip__trigger" ref="_triggerNode" v-on="events">
<slot></slot>
</div>
</template>
<slot name="default" v-else></slot>
  • 作用: 根据 virtualTriggering 决定是否渲染默认触发节点,或使用外部提供的虚拟触发节点。

10. 过渡动画与 Popper 销毁

1
2
3
4
5
6
<transition :name="transition" @after-leave="destroyPopperInstance">
<div class="vr-tooltip__popper" v-if="visible">
<slot name="content">{{ content }}</slot>
<div id="arrow" data-popper-arrow></div>
</div>
</transition>
  • 作用: 使用 Vue 过渡动画(如 fade),并在动画结束后销毁 Popper 实例。

11. 点击外部区域关闭

1
2
3
4
5
useClickOutside(containerNode, () => {
emits('click-outside');
if (props.trigger === 'hover' || props.manual) return;
visible.value && closeFinal();
});
  • 作用: 当点击外部区域时触发 click-outside 事件,并在非手动控制且非悬停模式下隐藏提示框。

12. 手动控制模式

1
2
3
4
5
if (props.manual) {
events.value = {};
outerEvents.value = {};
dropdownEvents.value = {};
}
  • 作用: 当 manualtrue 时,禁用自动触发逻辑,需通过 show()hide() 手动控制。

总结

  • 核心功能: 提供可定制的提示框组件,支持多种触发方式、位置定位和虚拟触发节点。
  • 扩展性: 通过 popperOptionstransition 自定义定位和动画。
  • 交互: 支持防抖、手动控制、虚拟触发节点和外部事件监听。