UNPKG

song-ui-u

Version:

vue3 + js的PC前端组件库

172 lines (146 loc) 5.32 kB
'use strict'; var vue = require('vue'); var index = require('../../../hook/use-namespace/index.cjs'); require('song-ui-pro-icon'); require('../../../hook/use-zindex/index.cjs'); var _pluginVue_exportHelper = require('../../../_virtual/_plugin-vue_export-helper.cjs'); const _sfc_main = /*#__PURE__*/Object.assign({ name: "x-tooltip", }, { __name: 'tooltip', props: { content: { type: String, required: true }, // 提示内容 position: { type: String, default: "top" }, // 位置:top/bottom/left/right trigger: { type: String, default: "hover" }, // 触发方式:hover/click delay: { type: Number, default: 300 }, // 延迟显示(仅 hover) }, setup(__props, { expose: __expose }) { __expose(); const ns = index.useNamespace("tooltip"); const props = __props; const isVisible = vue.ref(false); let timer = null; // 事件处理 const handleHover = (state) => { if (props.trigger !== "hover") return; clearTimeout(timer); timer = setTimeout(() => (isVisible.value = state), state ? props.delay : 0); }; const handleClick = () => { if (props.trigger == "click") { isVisible.value = !isVisible.value; } }; // 点击外部关闭(仅 click 模式) const clickOutsideHandler = (e) => { // 使用 ns.b() 获取正确的类名 if (!isVisible.value || !e.target.closest(`.${ns.b()}`)) { isVisible.value = false; } }; // 生命周期 vue.watchEffect(() => { if (props.trigger === "click") { document.addEventListener("click", clickOutsideHandler); } else { document.removeEventListener("click", clickOutsideHandler); } }); vue.onUnmounted(() => { document.removeEventListener("click", clickOutsideHandler); }); // 添加位置计算逻辑 const tooltipRef = vue.ref(null); const computedPosition = vue.ref(props.position); const updatePosition = () => { if (!tooltipRef.value) return; // const triggerEl = tooltipRef.value.parentElement; const triggerEl = tooltipRef.value.parentElement.querySelector(":first-child"); const tooltipEl = tooltipRef.value; const rect = triggerEl.getBoundingClientRect(); const tooltipRect = tooltipEl.getBoundingClientRect(); // 获取视口尺寸 const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; // 检查各个方向的可用空间 const spaces = { top: rect.top, bottom: viewportHeight - rect.bottom, left: rect.left, right: viewportWidth - rect.right, }; // 根据当前位置和可用空间自动调整 switch (props.position) { case "top": if (spaces.top < tooltipRect.height) { computedPosition.value = "bottom"; } break; case "bottom": if (spaces.bottom < tooltipRect.height) { computedPosition.value = "top"; } break; case "left": if (spaces.left < tooltipRect.width) { computedPosition.value = "right"; } break; case "right": if (spaces.right < tooltipRect.width) { computedPosition.value = "left"; } break; } }; // 监听显示状态变化时更新位置 vue.watch( () => isVisible.value, (val) => { if (val) { vue.nextTick(() => { updatePosition(); }); } } ); // 监听窗口大小变化 vue.onMounted(() => { window.addEventListener("resize", updatePosition); }); vue.onUnmounted(() => { window.removeEventListener("resize", updatePosition); }); const __returned__ = { ns, props, isVisible, get timer() { return timer }, set timer(v) { timer = v; }, handleHover, handleClick, clickOutsideHandler, tooltipRef, computedPosition, updatePosition, ref: vue.ref, watch: vue.watch, watchEffect: vue.watchEffect, onUnmounted: vue.onUnmounted, onMounted: vue.onMounted, nextTick: vue.nextTick, get useNamespace() { return index.useNamespace } }; Object.defineProperty(__returned__, '__isScriptSetup', { enumerable: false, value: true }); return __returned__ } }); function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return (vue.openBlock(), vue.createElementBlock("div", { class: vue.normalizeClass($setup.ns.b()), onMouseenter: _cache[0] || (_cache[0] = $event => ($setup.handleHover(true))), onMouseleave: _cache[1] || (_cache[1] = $event => ($setup.handleHover(false))), onClick: $setup.handleClick }, [ vue.renderSlot(_ctx.$slots, "default"), vue.createVNode(vue.Transition, { name: $setup.ns.b() }, { default: vue.withCtx(() => [ ($setup.isVisible) ? (vue.openBlock(), vue.createElementBlock("div", { key: 0, ref: "tooltipRef", class: vue.normalizeClass([$setup.ns.e('content'), $setup.ns.m('content', $setup.computedPosition)]) }, vue.toDisplayString($props.content), 3 /* TEXT, CLASS */)) : vue.createCommentVNode("v-if", true) ]), _: 1 /* STABLE */ }, 8 /* PROPS */, ["name"]) ], 34 /* CLASS, NEED_HYDRATION */)) } var tooltip = /*#__PURE__*/_pluginVue_exportHelper(_sfc_main, [['render',_sfc_render],['__file',"E:\\code\\my-code\\song-ui-ultra\\packages\\components\\tooltip\\src\\tooltip.vue"]]); module.exports = tooltip; //# sourceMappingURL=tooltip.vue.cjs.map