教你轻松解决Vue Dialog弹窗诟病
沈二到不行 人气:0摘要
相信用Vue框架多的老哥对弹窗的使用的问题都有一些使用上的诟病,本轮主要阐述针对组件封装不符合逻辑编写,如何最小化封装达成简化调用目的。
分析
常规的Vue前端UI组件如elment-ui、Iview、Ant Design Vue等UI组件库针对模态窗的封装基本都是套式的,MVVM大家基本都在提,从另外一个角度分析Dialog封装在实际使用上,弹窗过多时漫天的变量如何解决,我们把temlplate中的内容理解为表现层,script理解为逻辑层,虽然解决了数据的绑定问题,但说实在的,vue的逻辑层和表现层互相穿插使用还是相对存在一些问题,也许你会提Vue也支持Jsx写法,安装了插件也能实现React的写法和效果,此时我以模态窗的例子来说明一些问题
- elment-ui
- Iview
- Ant Design Vue大家在实践过程中,实现这样一个简单操作,点击明细->弹窗表单信息->确定调用数据保存接口 这个过程如一个业务处理中有很多的编辑弹窗,或者保存逻辑需要连贯性,还有区分会凭空使得一个处理变得很凌乱复杂。 可以看到一个弹窗,如果扩展3个data变量,两个方法。如果有10个弹窗,那么也变将会多出来310个属性和210个方法。 我们针对弹窗的调用习惯更倾向于layer和react这种随时取用的写法 那么问题来了,vue虽然号称支持jsx写法如下图,但却会失去拥有当前页面属性方法共享的部分权力,本质上来说,其实就是函数式组件乃至于后来都趋向的钩子函数或者叫组合式,其本质也就是上下文的共享。
优化办法
如果结合vue特点,要合并属性和方法,必然要封装模态窗为组件,但显示和确认,并不是一个链结构,由此就必须实现一个回调,但回调这种写法,往往是要在组件中进行一些约定,而且现在在Promise横行外加aysnc await 去JQ时代链式折磨的前提下,简单来讲,异步调用但采用同步写法。 如果把Promise比作 "线程" 那我们就需要一个调度,去控制在点击 “确认” 时结束。
- deferred对象就是jQuery的回调函数解决方案,$.Deferred 给我提供了思路,也就是把promise对象的reject和resolve开放出来
function generateDeferredPromise() { return (() => { let resolve; let reject; let p = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise: p, reject, resolve }; })(); }
- 完整的模态窗封装如下,可以看到我们在show的时候返回了promise对象,在确认的时候触发了回调
<template> <el-dialog :title="title" :visible.sync="drawer"> <slot /> <div slot="footer" class="dialog-footer"> <el-button @click="drawer = false">取 消</el-button> <el-button type="primary" @click="saveData">确 定</el-button> </div> </el-dialog> </template> <script> function generateDeferredPromise() { return (() => { let resolve; let reject; let p = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise: p, reject, resolve }; })(); } export default { name:'modal', props: { title: { type: String, default: undefined, }, handle:{ type:Function, default:(res)=>{}, } }, data() { return { drawer: false, promise:null, } }, mounted() { if(this.handle){ this.handle(this); } }, methods: { show() { this.drawer = true this.promise=new generateDeferredPromise(); return this.promise.promise; }, saveData(){ this.promise.resolve(); this.promise.promise.then(()=>{ this.drawer=false; }) } } } </script> <style> </style>
- 调用时如下,可以很轻松的变相达成函数式编程的特点,在调用时减去了2个属性和一个方法,10个弹窗由原本的30+20个减少为20。
<modal title="审批/反馈" ref="modal"> <el-descriptions :model="audit" class="margin-top" :column="1" border> <el-descriptions-item label="意见"> <el-radio-group v-model="audit.state"> <el-radio :label="true">通过</el-radio> <el-radio :label="false">不通过</el-radio> </el-radio-group> </el-descriptions-item> <el-descriptions-item label="内容"> <el-input type="textarea" v-model="audit.comment"></el-input> </el-descriptions-item> </el-descriptions> </modal> async handleAudit(row) { const { show } = this.$refs["modal"] || {}; show().then(async () => { //保存逻辑处理 }); },
总结
- 本质其实本次分享页并没有很多新意,这种引用式的封装,很多人也早都想到了,只不过感觉针对弹窗这块的封装,很多走了极端,要么就追求layer那种写法兼容习惯,要么干脆还是保留原样,只做一些特殊处理,属性还是原样保留了。
- 至于回调,我之前虽然用过一段,但还是觉得不慎习惯,因为偶然有个共享弹窗存在确认后逻辑不同的问题给我造成了困扰,觉得写法有点儿变态,因此做了一些尝试和延展,觉得算是比较良性的一个调用方式吧。
- 框架性的东西,我诧异的是,理论性的东西,一个比一个探的深,但涉及到便捷性,却很少有人去探究,乃至于框架性的东西除了UI和风格不同,写法也大同小异。
加载全部内容