今天一直在纠结dialog中的sync有什么用??
因为在官方文档的在线运行中,没有发现其他方法;
所以一度认定,sync就是起一个关闭弹层的作用;原本在子组件中使用el-dialog时,去掉sync修饰
的visible点击关闭按钮无法关闭弹窗,更让我确信就是这个用处
但是********************
加上sync后再次点击右上角的关闭按钮,此处报了个警告,有道翻译后是:
【避免直接改变道具,因为每当父组件重新呈现时,道具的值会被覆盖。相反,应根据道具的值使用数据或计算属性。道具被突变:“showDialog”】
/*弹窗子组件*/
<el-dialog
title="提示"
:visible.sync="showDialog"
width="35%"
>
/*父组件*/
<add-dep :show-dialog.sync="showDialog"
:current-node="currentNode"
@addDepts="getDepartmentsList" />
[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: "showDialog"
found in
---> <AddDep> at src/views/departments/components/add-dep.vue
此处报错的原因在于,我的showDialog是从父组件中调用过来的,但是此时点击关闭按钮的时候:visible.sync修改了showDialog的值,与官网不同的地方在于,官网中的变量是声明在data中的;
翻看了这部分的源码后发现:
源码中在data中定义了一个closed属性来控制弹窗的开关,并且监听了一个变量visible用来控制是否展示弹窗,此处就与我们使用的el-dialog关联起来了
不难看出,
在mounted 中判断了visible是否为true,为true且构建dom后调用了open打开弹窗并判断是否要追加到页面结构中;
watch中根据visible的val来控制closed的值从而来改变弹窗是否打开,与此同时,监听了在 Dialog 出现时锁定body 滚动
点击关闭按钮调用的handleClose方法,此方法中调用的hide才是点击关闭按钮真正关闭弹窗的方法
//copy部分源代码做解释,想看完整的建议问度娘
<template>
<transition
name="dialog-fade"
@after-enter="afterEnter"
@after-leave="afterLeave"
>
<div v-show="visible" class="el-dialog__wrapper" @click.self="handleWrapperClick">
<div
ref="dialog"
role="dialog"
aria-modal="true"
:aria-label="title || 'dialog'"
class="el-dialog"
:class="[{ 'is-fullscreen': fullscreen, 'el-dialog--center': center }, customClass]"
:style="style"
>
<div class="el-dialog__header">
<slot name="title">
<span class="el-dialog__title">{{ title }}</span>
</slot>
<button
v-if="showClose"
type="button"
class="el-dialog__headerbtn"
aria-label="Close"
@click="handleClose"
>
<i class="el-dialog__close el-icon el-icon-close" />
</button>
</div>
<div v-if="rendered" class="el-dialog__body"><slot /></div>
<div v-if="$slots.footer" class="el-dialog__footer">
<slot name="footer" />
</div>
</div>
</div>
</transition>
</template>
<script>
data() {
return {
closed: false
}
},
watch: {
// 是否显示 Dialog,支持 .sync 修饰符
visible(val) {
if (val) {
this.closed = false
this.$emit('open')
this.$el.addEventListener('scroll', this.updatePopper)
this.$nextTick(() => {
this.$refs.dialog.scrollTop = 0
})
if (this.appendToBody) {
document.body.appendChild(this.$el)
}
} else {
this.$el.removeEventListener('scroll', this.updatePopper)
if (!this.closed) this.$emit('close')
}
}
},
mounted() {
if (this.visible) {
this.rendered = true
this.open()
if (this.appendToBody) {
document.body.appendChild(this.$el)
}
}
},
methods: {
// 关闭dialog
handleClose() {
// 如果有beforeClose,执行beforeClose
if (typeof this.beforeClose === 'function') {
this.beforeClose(this.hide)
} else {
// 否则隐藏
this.hide()
}
},
// 隐藏dialog
hide(cancel) {
if (cancel !== false) {
this.$emit('update:visible', false)
this.$emit('close')
this.closed = true
}
}
}
</script>
结论:
将dialog直接使用时
<el-dialog>封装前(源码中)有一个visible属性来控制弹层是否显示,并且监听了弹层的值,sync是<el-dialog>里面定义的一个标识,用来双向绑定,修改了值就会触发源代码中的监听,从而运行$emit的逻辑
将dialog作为弹层子组件使用时,如果不对其进行一些设置,点击关闭后会以上警告且无法再次打开该弹窗。
可以去掉关闭按钮:show-close="false"和sync修饰符仅使用确认取消按钮中emit的方法来关闭弹层
<el-dialog
title="提示"
:visible="showDialog"
width="35%"
@close="closeFn"
>
// 添加子部门
async addDepartment() {
try {
await this.$refs.departForm.validate()
// 新增部门
await addDepartments({ ...this.departForm, pid: this.currentNode.id })
// 修改视图
this.$emit('addDepts')
// 提示消息
this.$message.success('成功添加子部门')
// 关闭弹层
this.$emit('update:showDialog', false)
} catch (error) {
console.log(error)
}
},
closeFn() {
// 重置数据 因为resetFields 只能重置 表单上的数据 非表单上的 比如 编辑中id 不能重置
this.departForm= {
name: '',
code: '',
manager: '',
introduce: ''
}
this.$refs.departForm.resetFields() // 重置校验字段
// 关闭弹层
this.$emit('update:showDialog', false)
}