Element中Message组件相信大家用的都不少,但你真的熟悉Message组件吗?
你不知道的Message
一般情况下,我们会这样去使用Message组件:
import { Message } from 'element-ui';
Message({
message: "调用成功",
type: "success",
})
Message.success("调用成功")
但是当组件渲染时,我们尝试点击键盘上的ESC键,会发现所有的Message弹窗都关闭了。这是怎么一回事呢??
我们再次尝试,在一个点击事件中,多次调用弹窗提示
<template>
<div @click="open">多次提示</div>
</template>
<script>
import { Message } from 'element-ui';
...
methods: {
open(){
Message.success("1")
Message.success("2")
Message.success("3")
Message.success("4")
Message.success("5")
Message.success("6")
},
},
...
</script>
当触发open事件时,我们再次点击键盘上的ESC键,所有的弹窗组件还是全部关闭了。
这时我们就要打开Message源码一探究竟了。
在源码element\packages\message\src\main.vue中存在上述一段代码
哦!!!这下我们明白了,原来在每次组件渲染完成时,都开启了一个keydown事件监听,如果我们按下的键keyCode === 27(按下键是Esc)时,就会去判断当前组件的closed状态,如果是没有关闭就会调用this.close() 关闭当前弹窗。
看到这,我们会想Message又是如何进行组件挂载和销毁的呢??
Message组件是如何进行挂载与销毁的
Message组件实现主要依赖于这两个文件:
挂载组件:
//main.js
...
import Main from './main.vue';
...
let MessageConstructor = Vue.extend(Main);
...
const Message = function(options) {
if (Vue.prototype.$isServer) return;
options = options || {};
if (typeof options === 'string') {
options = {
message: options
};
}
let userOnClose = options.onClose;
let id = 'message_' + seed++;
options.onClose = function() {
Message.close(id, userOnClose);
};
instance = new MessageConstructor({
data: options
});
instance.id = id;
if (isVNode(instance.message)) {
instance.$slots.default = [instance.message];
instance.message = null;
}
instance.$mount();
document.body.appendChild(instance.$el);
let verticalOffset = options.offset || 20;
instances.forEach(item => {
verticalOffset += item.$el.offsetHeight + 16;
});
instance.verticalOffset = verticalOffset;
instance.visible = true;
instance.$el.style.zIndex = PopupManager.nextZIndex();
instances.push(instance);
return instance;
};
当我们调用Message({ message: "调用成功", type: "success"}) 时,执行的就是上述Message方法。
首先,通过Vue.extend(Main) 创建一个”子类“,然后new MessageConstructor({data: options}) 实例化组件对象,最后通过instance.el) 完成组件的挂载(渲染)。
销毁组件:
//main.vue
<template>
<transition name="el-message-fade" @after-leave="handleAfterLeave">
<div
...
v-show="visible"
...
>
...
</div>
</transition>
</template>
<script type="text/babel">
export default {
data() {
...
visible: false,
...
}
...
watch: {
closed(newVal) {
if (newVal) {
this.visible = false;
}
}
},
...
methods: {
handleAfterLeave() {
this.$destroy(true);
this.$el.parentNode.removeChild(this.$el);
},
close() {
this.closed = true;
if (typeof this.onClose === 'function') {
this.onClose(this);
}
},
...
}
}
</script>
通过调用close方法,watch监听closed会将this.visible赋值为false,从而过渡钩子handleAfterLeave会被执行,this.el.parentNode.removeChild(this.$el) 会将节点从父节点中移除。
现在我们也能通过Vue.extend以及 $mount自己封装一个message组件了!!!
觉得对你有帮助的麻烦请点个小小的赞,谢谢。^o^