场景
vue + elementUi框架做后台管理系统时,需要使用弹出框 新增/编辑 内容时,可以将el-dialog二次封装,使代码简洁易维护。
子组件 addDialog.vue:
<template>
<div>
<el-dialog
title="新增"
:visible.sync="show"
@close="$emit('update:visible', false)"
>
<el-form>
<el-form-item label="姓名">
<el-input v-model="name" />
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
visible: {
type: Boolean,
default: false
}
},
data() {
return {
name: ' ',
show: this.visible,
};
},
watch: {
visible(val) {
this.show = val;
}
}
}
</script>
父组件中使用:
<template>
<div>
<button @click="handleAdd">打开/关闭</button>
<addDialog :visible.sync="addshow" />
</div>
</template>
<script>
import addDialog from "./addDialog.vue";
export default {
components: { addDialog },
data() {
return {
addshow: false,
};
},
methods: {
handleAdd() {
this.addshow = true;
}
}
};
</script>
在子组件中不能直接使用 props 的 visible来控制显示与隐藏,需要一个中间值 show 来控制。因为 el-dialog 关闭时会设置 visible 的值,子组件直接更改 props 的值会报错
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "visible"
所以,实现的思路是 父组件传递的参数添加 .sync 修饰,子组件中关闭弹框时使用 $emit('update:visible', false) 这样更改父组件中传递的 visible 的值,子组件中watch 到visible改变,就改变中间值show达到关闭的目的。
另外 <addDialog :visible.sync="addshow" /> 中 .sync 是下面代码的语法糖
<addDialog
:visible="addshow"
@update:visible="newVal => addshow = newVal"
/>
有 新增/修改 使用同一个弹出框的需求时,需要动态修改dialog中的内容,可以给子组件传递其他参数,在子组件watch中监听。之所以用watch监听,是因为子组件渲染只会执行一次created生命周期,如果非要将更改内容写在created中,就要配合 v-if 使用,将子组件用 v-if 包裹起来,每次都重新加载子组件,此时可以达到动态修改dialog内容的需求,但是el-dialog弹出的动画效果会消失。
更新:Vue3与Element plus
最新版Element Plus V2.9.8版本,dialog组件提供了Exposes handleClose 方法,关闭弹窗时不要用 emits 或直接改变visible的值,改用handleClose关闭弹窗,这样的话结合 v-if使用,关闭动画就不会消失了。
<el-dialog
v-model="visibleInner"
title="新建"
width="720px"
ref="dialogRef"
destroy-on-close
:close-on-click-modal="false"
@closed="关闭之后的操作()"
>
// ...
</el-dialog>
const dialogRef = ref(null);
// 取消按钮
function handleCancel() {
// visibleInner.value = false; // 这样关闭没有关闭动画
// emits("update:visible", false); // 这样关闭没有关闭动画
dialogRef.value.handleClose();
}
只有使用v-if控制自己封装的弹窗组件时才需要考虑动画问题,其他情况动画都是正常的。