在使用Vue + Element 实现需求时常会遇到单个Vue文件内出现多个弹窗需求,一般会这样写
<!--*.vue--> <template> <el-dialog :visible="visible1">弹框1</el-dialog> <el-dialog :visible="visible2">弹框2</el-dialog> </template> <script> export default { return { visible1: false, visible2: false } } </script>
这样的写法在文件内容多的时候容易出现模板臃肿的问题,而且需要外部管理弹窗组件的开关状态visible
可以如何改进
可以考虑将el-dialog封装成Service来使用
<!--*.vue--> <script> // 笔者习惯将src设置alias为@ import DialogService from '@/service/dialog' showDialog() { DialogService({ /* 弹框内需要用的data */}) } </script>
如何实现
首先需要定义DialogService的入口,内部通过
Vue.extend
I对组件模板进行继承
// src/service/dialog/index.js import Vue from 'vue' import dialogTemplate from './dialogTemplate.vue' const DialogConstructor = Vue.extend(dialogTemplate) import { isPlainObject } from 'lodash' export default options => { let instance return function() { // 单例模式,惰性返回弹窗实例 if (instance) { instance.visible = true return instance } instance = new DialogConstructor({ data: isPlainObject(options) ? { ...options } : {} }) instance.$mount() document.body.appendChild(instance.$el) instance.visible = true // 暴露实例方便后续的Ref操作 return instance } }
接下来是dialogTemplate的实现,可根据实际业务进行调整,以下代码仅作为参考
<!--src/service/dialog/dialogTemplate.vue--> <template> <el-dialog :title="title" :visible.sync="visible"> <el-table :height="300" :data="tblData"> <el-table-column props="prop1" label="col1" align="center" ></el-table-column> <el-table-column props="prop2" label="col2" align="center" ></el-table-column> <el-table-column Props="prop3" label="col3" align="center" ></el-table-column> </el-table> <div slot="footer" class="dialog-footer"> <el-button v-show="submitVisible" size="small" @click="handleCancel"> {{ cancelText }} </el-button> <el-button v-show="cancelVisible" size="small" type="primary" @click="handleSubmit" > {{ submitText }} </el-button> </div> </el-dialog> </template> <script> import { isFunction } from 'lodash' export default { data() { return { visible: false, title: '', labelWidth: '100px', content: null, tblData: [], /* footer */ submitVisible: true, submitText: '确定', onSubmit: null, cancelVisible: true, cancelText: '取消', onCancel: null } }, methods: { handleSubmit() { if (isFunction(this.onSubmit)) { this.onSubmit({ done: this._done }) } }, handleCancel() { if (isFunction(this.onCancel)) { this.onCancel({ done: this._done }) } }, _done() { this.visible = false }, _destory() { this.$destroy() } } } </script>
业务代码中使用
渲染一个带表格的弹窗
<!--*.vue--> <template> <el-button @click="showDialog">召唤表格</el-button> </template> <script> import DialogService from '@/service/dialog' export default { data() { return { dialogInstance: null } } methods: { showDialog() { this.dialogInstance = dialogService({ title: '带表格的Dialog', onCancel: ({ done }) => done() }) } } } </script>
随缘而来,乘风而去,山高海阔,自有我风采!
所属分类:
Vue.js