概览
el-dialog 是 element-ui 的一个组件,在本项目的管理端使用场景中,用于新增或编辑资源,vue 的优势之一就是组件化,所以新增或编辑也写成组件,经过几次改变后,我选择了以下的封装方式,更便于使用。
介绍
对需要弹窗展示的子组件中,直接用 el-dialog 组件,组件中提供一个能够控制 visible 显示的方法,本项目中显示的方法为 open() { this.visible = true },由父组件通过子组件的 ref 进行调用,控制 e-dialog 的显示。
场景
本项目中 el-dialog 主要用于展示、新增、编辑三种情况,新增与编辑一般会涉及到表单,即 el-form 组件的表单校验、表单提交等;展示与编辑时可能涉及到数据的接口获取等,所以将这些基础数据与 el-dialog 的一些常用方法,如 before-close 等做了 mixin 复用。
实现
mixin 的 modal.js
模态框的混入复用
export const modal = {
// 可能用到的一些数据初始化
data() {
return {
id: null, // 当前编辑的资源 ID
loading: false, // 展示与编辑时调用接口的加载状态
submitLoading: false, // 提交表单加载状态
visible: false, // 是否显示 el-dialog
isEdit: false, // 是否为编辑状态
form: {} // 默认表单
}
},
methods: {
/**
* @desc 父级调用打开模态框
* @param {Object} row 编辑时回显数据
*/
open(row) {
// 此处可通过接口获取需要的数据
// 有数据时为编辑状态
if (row) {
this.isEdit = true
// copy 传入数据,以防变更时影响到父组件数据
this.form = Object.assign(this.form, row)
}
// 显示 el-dialog
this.visible = true
// 清空表单验证,当el-dialog渲染显示时才可调用
this.$nextTick(() => {
this.$refs['form'] && this.$refs['form'].clearValidate()
})
},
// 对应 el-dialog 的 before-close 方法,关闭前回调,
// 若接口请求未处理完成,则禁止关闭
beforeClose(done) {
if (this.submitLoading) {
this.$message.warning('请等待操作完成后关闭')
} else {
done()
}
},
// 关闭模态框
close() {
// 重置表单内容
this.$refs['form'] && this.$refs['form'].resetFields()
// 初始化表单数据,vue 的 this.$options.data() 内部方法中存放这 data 的初始数据
this.form = this.$options.data().form
this.isEdit = false
// 关闭 el-dialog
this.visible = false
},
// 保存或更新时校验表单
submitForm() {
// 防止用户重新表单 ref 名称导致不存在时报错
if (this.$refs['form']) {
this.$refs['form'].validate((valid) => {
if (valid) {
this._submitForm()
} else {
return false;
}
});
} else {
this._submitForm()
}
},
// 表单提交 this.submit() 方法是在组件中定义的 ajax 请求方法
async _submitForm() {
this.submitLoading = true;
let res = await this.submit()
this.submitLoading = false;
if (res && res.code === 200) {
// 成功后将消息发送给父组件,以便父组件做处理,比如更新列表数据等
this.$emit("on-success");
this.visible = false;
}
}
},
}
子组件
子组件中使用 el-dialog 组件并无新加功能,注意与优化:
- 新增或编辑时
close-on-click-modal置为false,防止鼠标误触(特别是el-select多选情况)导致模态框关闭,表单数据被清空; - 新增或更新时,加上
before-close回调,防止用户在提交未完成时关闭模态框; - 模态框关闭时,需要重置表单数据、清空表单验证结果;
- 当表单内只有
<input type="text"></input>一个输入项时,需在表单中添加@submit.native.prevent方法,阻止按回车键时提交表单从而刷新页面。
<el-dialog
:title="isEdit ? '编辑资源' : '新建资源'"
:visible.sync="visible"
:close-on-click-modal="false"
:before-close="beforeClose"
@close="close()"
>
<!-- 表单 -->
<el-form
:model="form"
:rules="rules"
ref="form"
label-width="110px"
@submit.native.prevent
>
<el-form-item label="标题:" prop="title">
<el-input v-model="form.title" placeholder="请输入名称" />
</el-form-item>
</el-form>
<!-- 关闭弹窗或提交表单 -->
<div slot="footer">
<m-button type="cancel" @click="visible = false" />
<m-button type="submit" @click="submitForm()" :loading="submitLoading" />
</div>
</el-dialog>
import { createDemo, updateDemo } from "@/api/demo";
// 引入混入
import { modal } from "@/mixins/modal";
export default {
name: "DemoModal",
mixins: [modal],
data() {
return {
// 校验规则
rules: {
title: [
{
required: true,
message: "请输入标题",
trigger: "blur"
}
],
},
form: {
id: null,
title: "",
},
};
},
methods: {
// 父组件调用,编辑时需要传入被编辑的数据,以便在表单中回显
open(row) {
if (row) {
this.isEdit = true;
// copy 传入数据到表单,否则会影响到父组件数据
this.form = Object.assign(this.form, row);
}
this.visible = true;
},
// 表单提交,由 mixin 中的 submitFor() 方法调用
async submit() {
return this.isEdit
? await updateDemo(this.form.id, this.form)
: await createDemo(this.form);
}
}
};
使用
使用时,只需要引入 mixin 的 modal.js 与上面定义的弹窗表单组件,通过弹窗组件的 open() 方法即可控制弹窗的显示,代码量极少,且不影响 el-dialog 的任何 api 的使用。
<!-- 新增资源 -->
<m-button type="create" @click="showModal()" />
<m-table v-loading="loading" :data="list">
<m-table-column prop="title" min-width="100" label="标题" />
<m-table-column prop="content" min-width="100" label="内容" />
<m-table-column fixed="right" width="80" label="操作">
<template slot-scope="scope">
<!-- 编辑资源,需传入资源信息以在表单中回显 -->
<m-button type="edit" @click="showModal(scope.row)" />
</template>
</m-table-column>
</m-table>
<!-- 新增或编辑的表单模态框,数据变更成功后刷新列表数据 -->
<demo-modal ref="modal" @on-success="getData()" />
// 引入接口
import { getDemoList } from "@/api/demo";
// 引入组件(页面组件一般放于该父级下的 components 文件夹中)
import DemoModal from "./components/DemoModal";
export default {
name: "DemoList",
components: {
DemoModal,
},
data() {
return {
loading: false,
list: []
};
},
mounted() {
this.getData();
},
methods: {
// 获取数据列表
async getData() {
this.loading = true;
let { code, data } = await getDemoList();
this.loading = false;
if(code === 200) {
this.list = data;
}
},
// 显示新增或编辑的模态框
showModal(row) {
this.$refs["modal"].open(row);
},
}
})
扩展
如果 el-dialog 中的内容较为复杂,如在关闭前或者关闭时需要做一些事情处理,可在组件中重写对应的方法覆盖,如下:
methods: {
// 关闭前做一些事务处理
async beforeClose() {
try {
await this.$confirm("还有文件未操作, 确定要离开吗?", "提示", {
type: "warning",
});
} catch (e) {
return;
}
this.visible = false;
this.$emit("on-close");
},
// 关闭模态框
close() {
// 重置 data 数据,this.$options.data() 方法中存放着 data 的初始化数据
this.data = this.$options.data();
this.visible = false;
}
}
慕影网管理端介绍文章
慕影网管理端演示地址
慕影网管理端源码地址
慕影网管理端开发文档
慕影网管理端接口文档
本项目会长期更新