UNPKG

birdpaper-ui

Version:

一个通用的 vue3 UI组件库。A common vue3 UI component library.

201 lines (200 loc) 5.83 kB
import { defineComponent, ref, onMounted, nextTick, onBeforeUnmount, watch, createVNode, h, Teleport, Transition, withDirectives, vShow, resolveDirective } from "vue"; import { getWrapperSize, getPositionData, getWrapperPositionStyle } from "./core.js"; import { on, off, throttle } from "../../utils/util.js"; import { vClickOutside } from "../../directives/clickOutside.js"; import { getScrollElements } from "../../utils/dom.js"; const _trigger = /* @__PURE__ */ defineComponent({ name: "Trigger", directives: { clickOutside: vClickOutside }, props: { popupVisible: { type: Boolean, default: false }, /** 触发方式 */ trigger: { type: String, default: "click" }, /** 弹出位置 */ position: { type: String, default: "bottom" }, /** 距离弹出位置的偏移量 */ popupOffset: { type: Number, default: 10 }, /** 距离弹出位置的移动距离 */ popupTranslate: { type: Array, default: [0, 0] }, /** 弹出层是否填充触发器宽度 */ autoFitWidth: { type: Boolean, default: false }, /** 过渡动画名称 */ transition: { type: String, default: "fade" }, /** 点击其他元素关闭触发器 */ clickOutside: { type: Boolean, default: true }, /** 是否禁用 Disabled or not */ disabled: { type: Boolean, default: false }, /** 隐藏触发器 */ hideTrigger: { type: Boolean, default: false }, /** 是否跟随滚动元素更新 */ updateAtScroll: { type: Boolean, default: false }, /** 是否在滚动时关闭 */ scrollToClose: { type: Boolean, default: false }, /** 滚动触发关闭的时间 */ scrollToCloseTime: { type: Number, default: 400 } }, emits: ["update:popupVisible"], setup(props, { emit, slots }) { const name = "bp-trigger"; const triggerRef = ref(); const wrapperRef = ref(); const visible = ref(props.popupVisible || false); const clickOutsideLock = ref(true); const scrollElements = ref([]); const handleClick = () => { if (props.trigger === "hover" || props.disabled) return; updateVisible(!visible.value); handleResize(); }; const handleMouseEnter = () => { if (props.trigger === "click") return; updateVisible(true); handleResize(); }; const handleMouseLeave = () => { if (props.trigger === "click") return; updateVisible(false); }; const handleResize = () => { if (!triggerRef.value || !visible.value) return; const wrapperSize = getWrapperSize(wrapperRef.value); const { top, left, width } = getPositionData(triggerRef.value.children[0], props.position, { ...wrapperSize }, props.popupTranslate, props.popupOffset, props.autoFitWidth); const styleStr = getWrapperPositionStyle(top, left, visible.value, props.autoFitWidth ? width : null); wrapperRef.value.setAttribute("style", styleStr); if (props.scrollToClose && visible.value) { setTimeout(() => { updateVisible(false); }, props.scrollToCloseTime); } }; const onClickOutside = () => { if (!props.clickOutside) return; !clickOutsideLock.value && updateVisible(false); }; const updateVisible = (val, delay = 100) => { visible.value = val; emit("update:popupVisible", visible.value); nextTick(() => { setTimeout(() => { if (props.trigger === "click") { clickOutsideLock.value = !visible.value; } }, delay); }); }; onMounted(() => { nextTick(() => { on(window, "resize", throttle(handleResize)); if (props.updateAtScroll) { scrollElements.value = getScrollElements(triggerRef.value); for (const item of scrollElements.value) { on(item, "scroll", throttle(handleResize)); } } }); }); onBeforeUnmount(() => { off(window, "resize", throttle(handleResize)); off(window, "scroll", throttle(handleResize)); if (props.updateAtScroll) { scrollElements.value = getScrollElements(triggerRef.value); for (const item of scrollElements.value) { off(item, "scroll", throttle(handleResize)); } } }); watch(() => props.popupVisible, (v) => { visible.value = v; clickOutsideLock.value = visible.value; }); const render = () => { var _a, _b; const children = ((_a = slots.default) == null ? void 0 : _a.call(slots)) || []; return props.hideTrigger ? (_b = slots.content) == null ? void 0 : _b.call(slots) : createVNode("div", { "class": name, "ref": triggerRef, "id": "triggerRef" }, [h(children[0], { onClick: handleClick, onMouseenter: handleMouseEnter, onMouseleave: handleMouseLeave }), createVNode(Teleport, { "to": "body" }, { default: () => [createVNode(Transition, { "name": props.transition, "appear": true }, { default: () => { var _a2; return [withDirectives(createVNode("div", { "ref": wrapperRef, "class": `${name}-wrapper`, "onMouseenter": handleMouseEnter, "onMouseleave": handleMouseLeave }, [(_a2 = slots.content) == null ? void 0 : _a2.call(slots)]), [[vShow, visible.value], [resolveDirective("clickOutside"), onClickOutside]])]; } })] })]); }; return render; } }); export { _trigger as default };