写在最前
看官们好,我叫JetTsang,之前都是在掘金潜水来着,现在偶尔做一些内容输出吧。
引出
在vue2当中,全局组件比如弹窗组件如何封装呢?
有些小伙伴可能就简单的封装一个,这种功能也是很完备的 缺点:需要引入额外响应式变量,方法去控制 优点:像el-dialog一样,适合需要定制性更大的场景
那么对于定制性要求更小的场景,因此适合展示较为简单的内容,ElementUI是推荐: messageBox
组件,
看下它的用法:
这种类似于原生alert弹窗
的,就是函数式调用
,那么如何封装一个这样的组件呢? 下面会一一道来
如何封装?
为什么能this.$alert
?
这个官方给出了答案
就是利用原型链
javascript
Vue.prototype.$alert = function(message, title, options){
// 这里写逻辑
}
在$alert
当中怎么将弹窗组件创建出来?
看一下脚手架的工程文件,main.js
javascript
import Vue from "vue"
import App from "./App.vue"
const vm = new Vue({
render: (h) => h(App),
});
vm.$mount("#app")
这里的过程其实就是,
- 创建Vue实例(new Vue)
- 创建实例的时候,会调用render方法生成vNode(虚拟节点),其中的参数
h函数
是一个用来创建 vNode 的辅助函数。能将引入的APP组件
,变成vNode
- 最后实例挂载(
$mount
)到#app
这个真实dom当中
其实$alert
里面做的事情无非就是这样嘛,将我们的.vue组件,挂载到真实dom下
可以看到el的MessageBox 是挂在body下的
那么来实现一个自己的Modal
回到之前开头实现Modal,分别3个属性,2个自定义事件
内部方法构成:
前面提到了,只需要构造一个用于创建和挂载的函数,然后挂载到Vue.prototype即可全局调用
现在的目标就是构造这样一个函数
新建一个index.js,
javascript
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
const vm = new Vue({
render:(h) => h(Modal)
})
// 创建游离节点
const div = document.createElement('div')
// 放到body上
document.body.appendChild(div)
// 将vm挂载到这个节点上
vm.$mount(div)
}
打印一下这个vm
可以看到$el这一项是一个注释节点,因为我们设计的是v-if,此时没命中,因此会创建一个注释节点。
此时我们需要将showModal等参数传进去,该怎么办呢?
h函数就派上用场了,它的第2个参数可以传配置项
(就是.vue
里面的配置项)进去
javascript
h(Modal,{props:{showModal:true}})
这样子就有渲染了Modal了,但这个h函数的第2个参数只能传入包含模板相关属性(例如 props
、class
、style
等),如果要传入方法的话,只能另寻他法了
救星:VueExtend
所幸Vue提供了Vue.extend
从官网可以看到,extend需要传入一个配置项,但我们Modal.vue
组件已经写好了呀,总不能重新写一份到template
,或者写一个render
函数吧?
知道你很急,但你先别急,此时你就要知道.vue文件,被引入之后是什么?
.vue组件
究竟是啥???
打印一下Modal
这不就是一个对象嘛,options配置项
嘛
回忆一下.vue当中,是怎么写代码的
同时vue的编译器帮我们把<template>标签
里的内容编译成了render函数
啦
改造
所以就可以利用vue.extend进行改造啦
javascript
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
const ModalCtor = Vue.extend(Modal)
const modalVM = new ModalCtor({
propsData: {
showModal: true,
title: "JetTsang's Title",
text:"这是text"
},
data() {
return { }
},
mounted(){
console.log('mounted了')
},
methods:{
传入的方法(){
console.log('Hello JetTsang')
}
}
})
const div = document.createElement('div')
document.body.appendChild(div)
modalVM.$mount(div)
}
打印一下这个modalVM
,这就是1个vue组件了啊,可以通过写配置项来传入方法和属性了.
组件销毁和卸载
可以借助下面的流程
perl
// `$destroy()` 方法会触发 Vue 实例的生命周期钩子函数 `beforeDestroy` 和 `destroyed`
modalVM.$destroy()
// 真实dom的移除,调用HTMLElement的原生方法remove
modalVM.$el.remove()
最后 $modal(message, title, options)
的参数设计,相信难不倒各位
promise调用的实现
这里是有promise的调用形式啊
其实就是在index.js
暴露的$modal
函数当中返回一个promise嘛,我们直接用promise包装一下即可:
javascript
import Vue form 'vue'
import Modal from "./Modal.vue"
export default function $modal (){
const ModalCtor = Vue.extend(Modal)
// 返回1个promise实例
return new Promise((resolve,reject)=>{
const modalVM = new ModalCtor({
methods:{
// 确认
_confirm(){
// 在这里调用
resolve()
console.log('Hello JetTsang')
}
}
})
const div = document.createElement('div')
document.body.appendChild(div)
modalVM.$mount(div)
})
}
当然这里面方法也是多种多样,相信诸君一定比我想的好。
总结
这种函数式全局组件的封装,比较考验你对vue组件本质的理解。
如果觉得本文对你有帮助,麻烦点一下赞👍