el-dialog组件二次封装
前端到处需要用到e-dialog,对dialog的样式,close处理,visible处理的重复性代码很多,于是我们尝试进行二次封装。
# 现有问题
项目中el-dialog使用频率很高,到处都会出现相同逻辑,比如
<template>
<el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%">
<span>这是一段信息</span>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogVisible = false">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
data() {
return {
dialogVisible: false
};
},
};
</script>
visible处理的重复性代码很多,打算对其进行进一步封装。
# 设想
最好情况下,我们希望dialog组件在调用的地方能像普通组件一样,接受是否显示的参数即可,而不是每次交给调用处处理打开关闭的逻辑。
<template>
<el-button type="text" @click="dialogVisible = true">点击打开 Dialog</el-button>
<dialog-component :visible.sync="dialogVisible"></dialog-component>
</template>
<script>
export default {
data() {
return {
dialogVisible: false
};
},
};
</script>
vue2之后,子组件不再推荐直接修改父组件数据,所以不能直接修改visible的值,否则会报错
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,因为每当父组件重新渲染时,该值都会被覆盖。而是根据道具的值使用数据或计算属性。
真正的原因:
在 Vue2.X 中,父组件传给子组件的 props 属性是不允许改变的,因为在新的渲染机制中,每当父组件重新渲染时,子组件都会被重新覆盖,所以 props 属性,在子组件内部应该被看做是不可变对象。所以我们必须借助中间变量来做缓冲,通过中间变量的改变发送事件给父组件,父组件接收到后,再对 props 进行更改。
对此我们需要如此处理:
<template>
<el-dialog :visible.sync="dialogVisible" :before-close="close">
<slot />
</el-dialog>
</template>
<script>
export default {
name: 'DialogComponent',
props: {
dialogVisible: {
type: Boolean,
default: false
}
},
methods: {
close() {
this.$emit('update:dialogVisible', false)
},
}
}
</script>
# 更新下
vue2.4之后,增加的特性 $attrs $listeners,配合使用更加无缝。还可以将使用最多的表单编辑也封装进来
<template>
<el-dialog
v-bind="$attrs"
:visible.sync="dialogVisible"
:before-close="close"
v-on="$listeners"
>
<div class="dialog-content">
<el-form ref="elForm" :model="formData" :rules="rules" v-bind="$attrs">
<slot />
</el-form>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="submit">确 定</el-button>
</span>
</el-dialog>
</template>
<script>
export default {
name: 'DialogForm',
props: {
dialogVisible: {
type: Boolean,
default: false
},
rules: {
type: Object,
default: () => {
}
},
form: {
type: Object,
default: () => {
}
}
},
data() {
return {
formData: {}
}
},
watch: {
form: {
handler(val) {
this.formData = { ...val }
},
deep: true,
immediate: true
}
},
methods: {
onClose() {
this.$refs['elForm'].resetFields()
},
close() {
this.formData = {}
this.$emit('update:dialogVisible', false)
},
submit() {
this.$refs['elForm'].validate(valid => {
if (!valid) return
this.$emit('submit', { ...this.formData })
this.close()
})
}
}
}
</script>
# 使用示例
Copy