封装VueElement的dialog弹窗组件
我本没有想着说要封装⼀个弹窗组件,但有同⾏的朋友在问我,⽽且弹窗组件也确实在项⽬开发中⽤的⽐较多。思前想后,⼜本着样式统⼀且修改起来⽅便的原则,还是再为⼤家分享⼀个我所封装的弹窗组件吧。
其实,并不是所有封装组件的⽅式都是⼀成不变的,你可以采⽤函数式组件这种能提⾼性能的⽅式,也可以使⽤带有状态和⽣命周期的普通组件的封装⽅式。但像dialog这种包含很多点击事件如确定或提交事件、取消或重置事件、右上⾓那个⼩叉叉的关闭事件等,⼜有可能包含嵌套其他组件如表格组件、表单组件、树形组件、穿梭框组件等的公共组件,其成分略微复杂,功能不太单⼀,你若要采⽤函数式组件的⽅式来封装也不是不可以,只是可能xue微要⿇烦⼀些,我⾃⼰建议是不采⽤这种封装⽅式,就采⽤普通的封装⽅式就好。
⾄于普通组件的封装⽅式,我想⼤家平时在开发的过程中对所接触的普通组件即带有状态和⽣命周期,也能快乐地使⽤this关键词的组件已经是⾮常熟悉了,所以这种封装⽅式我就不会再做过多的介绍了。以下是具体的实现过程。照例还是先来张效果图:
1、所封装的弹窗组件dialog.vue
class=\"el-dialog-cus\" v-bind=\"attributes\" :visible=\"visible\":before-close=\"beClose\" append-to-body
:close-on-click-modal=\"false\" v-on=\"on\" >
{{btnTxt[0]}}
{{btnTxt[1]}}
对于以上的⼀些代码,我需要做⼀些特别的说明:
这段代码是弹窗的插槽,给弹窗中加⼊的主体内容都会出现在这⾥。为什么要在slot上加⼀个v-if的判断呢?你猜... 哈哈哈哈哈哈,其实是为了防⽌在弹窗中嵌套⼀些其他组件时,那些组件的⽣命周期只会执⾏⼀次的问题出现。open(ok) {
this.ok = ok;
this.visible = true; this.visibleSlot = true; return this.$nextTick();}
这段代码是弹出弹窗的⽅法,为的是在使⽤弹窗组件时,我们只需点击⼀个按钮并使⽤ref来获取弹窗组件的这个⽅法即可打开弹窗,剩下的关闭弹窗的操作就交给弹窗的确定或取消按钮来完成即可。我们不⽤再额外的写关闭弹窗的⽅法并将关闭弹窗的props参数传给弹窗组件。另外,在打开弹窗的⽅法中我还保存了⼀个ok事件,这个ok事件是⽤于在点击了弹窗组件的确定或提交按钮后所触发的回调函数。⽐如我们点击了弹窗的提交按钮,我们需要调⼀个接⼝来完成数据的存储或修改,那么这个ok事件就是为它实现的,毕竟弹窗组件充当的只是⼀个我们⽤于处理业务逻辑的中间桥梁。
另外,在这段代码的最后返回了⼀个nextTick,nextTick是将回调函数延迟在下⼀次DOM更新数据后调⽤,简单的理解就是当数据更新了,在DOM中渲染后,⾃动执⾏该函数。我们平时在操作DOM时⽤到它的情况就⽐较多,⽽我们的通常⽤法是:this.$nextTick(() => {}),但其实这个⽅法还返回了⼀个Promise对象,所以我们还可以这么⽤:this.$nextTick().then(() => {})。那么这⾥为什么要将这个⽅法返回呢?原因⾃然是需要在打开弹窗后去获取弹窗中的DOM元素,因为当打开弹窗时,⾥边的DOM元素还没有渲染完成,此时我们是获取不到⾥边的DOM节点的。confirm() {
let cancel = () => this.cancel(); this.ok(cancel);
this.autoClose && cancel();}
这段代码是在点击弹窗的确定或提交按钮时触发的,但为什么要给⼀个之前保存的ok回调函数传⼀个关闭的⽅法作为参数呢,这是因为有时我们在点击了确定或提交的按钮后并不想⽴即关闭这个弹窗,⽽是想在⼏秒钟的倒计时后再关闭这个弹窗并跳转到其他页⾯,亦或是在A弹窗的基础上⼜弹出另外⼀个B弹窗,在B弹窗的基础上⼜弹出⼀个C弹窗。关闭C弹窗时,还能看到B弹窗,⽽不⽤在A弹窗的基础上通过点击事件再弹出B弹窗。这个时候就需要把关闭的⽅法当作参数传递给ok回调函数,让调⽤弹窗组件的⼈⾃⾏控制在什么时候关闭弹窗,这难道不⾹吗?只不过这个时候可能需要多给弹窗组件传⼀个参数autoClose来通知它是不是需要前端⾃⾏控制什么时候来关闭弹窗,毕竟弹窗组件在⼤多数情况下都是点击了确定或提交按钮后就直接被关闭了。beClose(done) { done();
this.beforeClose(); this.cancel();}
这段代码是弹窗组件的关闭前before-close⽅法,element的官⽅解释是“关闭前的回调,会暂停Dialog的关闭”,官⽅还给了⼀个特别的说明:
before-close仅当⽤户通过点击关闭图标或遮罩关闭Dialog时起效。如果你在footer具名slot⾥添加了⽤于关闭Dialog的按钮,那么可以在按钮的点击回调函数⾥加⼊before-close的相关逻辑。
它接收⼀个参数done,⽤于关闭Dialog。⽽this.beforeClose()是⽤来⾃定义关闭前所要做的⼀些事情的⽅法。
还有⼀点需要注意的是:普通组件所有未声明的属性都会被解析到$attrs⾥⾯,并⾃动挂载到组件根元素上⾯。因为本次封装的弹窗组件的外⾯已经没有根元素了,也就是标签el-dialog的外⾯没有再包裹⼀层⽗标签,所以前边这句话的意义已经不⼤了。如果标签el-dialog的外⾯⼜包裹了⼀层div,那么那句话就有意义了,也就是说这些未声明的属性也会出现在最外层的div上,如果不想让这些未声明的属性也出现在最外层的div上,那么就可以⽤inheritAttrs:false来禁⽌。但本次封装的弹窗组件的外⾯没有根元素,所以加不加这个inheritAttrs:false都⽆所谓了。2、弹窗组件的使⽤:
以上具体的使⽤⽅法中:open() {
this.$refs.dialog.open(cancel => { // cancel();
console.log('点击提交按钮了') });}
这段代码就是⽤来打开或弹出弹窗组件,采⽤的是ref获取弹窗组件的open⽅法,并向弹窗组件的open⽅法传⼀个回调函数,⽽这个回调函数的参数就是组件中ok事件触发时所返回的函数参数cancel,如果不需要前端来⾃⾏控制弹窗的关闭,则不接收这个cancel参数即可。