ivue-material-plus
Version:
A high quality UI components Library with Vue.js
188 lines (172 loc) • 3.99 kB
text/typescript
import { nextTick, defineComponent } from 'vue';
import { createPopper } from '@popperjs/core';
export default defineComponent({
emits: [
'on-popper-show',
'on-popper-hide',
'on-created',
'update:modelValue',
],
props: {
reference: {
type: Object,
},
popper: {
type: Object,
},
/**
* 弹窗的展开方向
*
* @type {String}
*/
placement: {
type: String,
default: 'bottom',
},
/**
* 箭头当前间距 左右 上下
*
* @type {Array}
*/
offset: {
default: [0, 0],
},
/**
* 显示隐藏
*
* @type {Boolean}
*/
modelValue: {
type: Boolean,
default: false,
},
/**
* 动画
*
* @type {String}
*/
transition: String,
/**
* 默认选项
*
* @type {Object}
*/
options: {
type: Object,
default() {
return {
modifiers: [
// 这决定了是否使用 GPU 加速样式来定位 popper
{
name: 'computeStyles',
options: {
gpuAcceleration: false, // true by default
},
},
//检测溢出
{
name: 'preventOverflow',
options: {
rootBoundary: 'viewport',
},
},
],
};
},
},
},
// 在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用。
updated() {
nextTick(() => {
this.updatePopper();
});
},
// 销毁
beforeUnmount() {
if (this.popperJS) {
this.popperJS.destroy();
}
},
methods: {
// 创建pppper
createPopper() {
// 位置
if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
return;
}
// 选项
const options = this.options;
// 节点
const popper = this.popper || this.$refs.popper;
// 参考位置
const reference = this.reference || this.$refs.reference;
if (!popper || !reference) return;
// 销毁
// eslint-disable-next-line no-prototype-builtins
if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
this.popperJS.destroy();
}
// 方向
options.placement = this.placement;
// 箭头当前与参考重叠,我们可以使用修改器给它一个距离offset
if (!options.modifiers[3]) {
options.modifiers[3] = {
name: 'offset',
options: {
offset: this.offset,
},
};
}
// 创建
options.onFirstUpdate = () => {
nextTick(() => {
this.updatePopper();
});
this.$emit('on-created', this);
};
this.popperJS = createPopper(reference, popper, options);
},
// 更新
updatePopper() {
this.popperJS ? this.popperJS.update() : this.createPopper();
},
// 销毁
popperDestroy() {
// 显示
if (this.visible) {
return;
}
this.popperJS.destroy();
this.popperJS = null;
},
},
watch: {
// 显示隐藏
modelValue: {
immediate: true,
handler(val: boolean) {
this.visible = val;
this.$emit('update:modelValue', val);
},
},
// 显示隐藏
visible(value: boolean) {
// 显示
if (value) {
// 增加zIndex
if (this.handleIndexIncrease) {
this.handleIndexIncrease();
}
// 更新
this.updatePopper();
this.$emit('on-popper-show');
}
// 隐藏
else {
this.$emit('on-popper-hide');
}
// update
this.$emit('update:modelValue', value);
},
},
});