song-ui-u
Version:
vue3 + js的PC前端组件库
172 lines (146 loc) • 5.32 kB
JavaScript
;
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