birdpaper-ui
Version:
一个通用的 vue3 UI组件库。A common vue3 UI component library.
200 lines (199 loc) • 5.79 kB
JavaScript
"use strict";
const vue = require("vue");
const core = require("./core.js");
const util = require("../../utils/util.js");
const clickOutside = require("../../directives/clickOutside.js");
const dom = require("../../utils/dom.js");
const _trigger = /* @__PURE__ */ vue.defineComponent({
name: "Trigger",
directives: {
clickOutside: 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 = vue.ref();
const wrapperRef = vue.ref();
const visible = vue.ref(props.popupVisible || false);
const clickOutsideLock = vue.ref(true);
const scrollElements = vue.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 = core.getWrapperSize(wrapperRef.value);
const {
top,
left,
width
} = core.getPositionData(triggerRef.value.children[0], props.position, {
...wrapperSize
}, props.popupTranslate, props.popupOffset, props.autoFitWidth);
const styleStr = core.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);
vue.nextTick(() => {
setTimeout(() => {
if (props.trigger === "click") {
clickOutsideLock.value = !visible.value;
}
}, delay);
});
};
vue.onMounted(() => {
vue.nextTick(() => {
util.on(window, "resize", util.throttle(handleResize));
if (props.updateAtScroll) {
scrollElements.value = dom.getScrollElements(triggerRef.value);
for (const item of scrollElements.value) {
util.on(item, "scroll", util.throttle(handleResize));
}
}
});
});
vue.onBeforeUnmount(() => {
util.off(window, "resize", util.throttle(handleResize));
util.off(window, "scroll", util.throttle(handleResize));
if (props.updateAtScroll) {
scrollElements.value = dom.getScrollElements(triggerRef.value);
for (const item of scrollElements.value) {
util.off(item, "scroll", util.throttle(handleResize));
}
}
});
vue.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) : vue.createVNode("div", {
"class": name,
"ref": triggerRef,
"id": "triggerRef"
}, [vue.h(children[0], {
onClick: handleClick,
onMouseenter: handleMouseEnter,
onMouseleave: handleMouseLeave
}), vue.createVNode(vue.Teleport, {
"to": "body"
}, {
default: () => [vue.createVNode(vue.Transition, {
"name": props.transition,
"appear": true
}, {
default: () => {
var _a2;
return [vue.withDirectives(vue.createVNode("div", {
"ref": wrapperRef,
"class": `${name}-wrapper`,
"onMouseenter": handleMouseEnter,
"onMouseleave": handleMouseLeave
}, [(_a2 = slots.content) == null ? void 0 : _a2.call(slots)]), [[vue.vShow, visible.value], [vue.resolveDirective("clickOutside"), onClickOutside]])];
}
})]
})]);
};
return render;
}
});
module.exports = _trigger;