1.问题描述
- 在vue项目中,对于dialog弹框的使用频率较高,如果是增删改查页面,几乎是每个页面都需要用到;
- 如果将dialog封装成一个组件,在利用slot插槽,每个页面应用起来会更加简单;
- 查阅了vuejs官网,发现v-model也可以应用到自定义组件上,model属性就是获取到自定义组件的prop、event,考虑采用一下方式实现dialog的封装。
2. 最开始想到的dialog封装
<template>
<!-- 父组件 -->
<div>
<h3>自定义dialog组件</h3>
<el-button type="primary" @click="openDialogHandler"
>点击展开对话框</el-button
>
<!-- 封装的el-dialog组件 -->
<detail-dialog :dialogVisible="dialogVisible" :title="title">
<div slot="body">
自定义组件v-model实践,可以直接应model,其中有prop、event两个属性
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</div>
</detail-dialog>
</div>
</template>
<script>
import DetailDialog from "./components/dialog.vue";
export default {
components: { DetailDialog },
data() {
return {
dialogVisible: false,
title: "",
};
},
mounted() {},
methods: {
openDialogHandler() {
this.dialogVisible = true;
this.title = "查看自定义组件使用v-model";
},
},
};
</script>
<style scoped>
</style>
<template>
<!-- 子组件 -->
<div>
<el-dialog
:title="title"
:visible.sync="dialogVisible"
width="600px"
>
<slot name="body"/>
<span slot="footer">
<slot name="footer"></slot>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
},
title:{
type:String,
default:'自定义组件提示'
}
},
data() {
return {};
},
mounted() {},
methods: {},
};
</script>
<style lang="" scoped>
</style>
结果:
子组件是禁止直接修改props的,所以控制台会报错。
这时候考虑新增一个中间变量innerVisible,来拦截props[visible]的修改和获取。注意:在父组件传值的时候需要加上.sync,这里可以查看vuejs官网
<!-- 父组件 -->
<detail-dialog :dialogVisible.sync="dialogVisible" :title="title">
<div slot="body">
自定义组件v-model实践,可以直接应model,其中有prop、event两个属性
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</div>
</detail-dialog>
<template>
<!--子组件 -->
<div>
<el-dialog
:title="title"
:visible.sync="innerVisible"
width="600px"
>
<slot name="body"/>
<span slot="footer">
<slot name="footer"></slot>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
props: {
dialogVisible: {
type: Boolean,
default: false
},
title:{
type:String,
default:'自定义组件提示'
}
},
data() {
return {};
},
mounted() {},
computed:{
innerVisible:{
get:function(){
return this.dialogVisible;
},
set:function(val){
this.$emit('update:dialogVisible', val);
}
}
},
methods: {},
};
</script>
<style lang="" scoped>
</style>
这样子就不会报错啦!!!!
查看vuejs官网会发现,自定义组件也可以应用v-model,然后在子组件中通过model中的prop、event操作实现props值的双向传递。
<!-- 封装的el-dialog组件 -->
<detail-dialog v-model="dialogVisible" :title="title">
<div slot="body">
自定义组件v-model实践,可以直接应model,其中有prop、event两个属性
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false">关闭</el-button>
</div>
</detail-dialog>
<template>
<div>
<el-dialog
:title="title"
:visible.sync="innerVisible"
width="600px"
>
<slot name="body"/>
<span slot="footer">
<slot name="footer"></slot>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
model:{
prop:'dialogVisible',// 修改 v-model 绑定的props名称
event:'toggle' // 修改 v-model 绑定的自定义事件名
},
props: {
dialogVisible: {
type: Boolean,
default: false
},
title:{
type:String,
default:'自定义组件提示'
}
},
data() {
return {};
},
mounted() {},
computed:{
innerVisible:{
get:function(){
return this.dialogVisible;
},
set:function(val){
this.$emit('update:toggle', val);
}
}
},
methods: {},
};
</script>
<style lang="" scoped>
</style>
继续优化,将dialog的相关方法封装到mixins里,以后页面用就可以直接引入mixin就可以了!
<template>
<!--dialog子组件-->
<div>
<el-dialog
:title="title"
:visible.sync="innerVisible"
width="600px"
>
<slot name="body"/>
<span slot="footer">
<slot name="footer"></slot>
</span>
</el-dialog>
</div>
</template>
<script>
import dialog from '@/mixins/dialog.js'
export default {
mixins:[dialog],//引入mixin
data() {
return {};
},
mounted() {},
computed:{
},
methods: {},
};
</script>
<style lang="" scoped>
</style>
mixins.js
export default {
model: {
prop: 'dialogVisible',
event: 'toggle'
},
props: {
dialogVisible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '自定义组件提示'
}
},
computed: {
innerVisible: {
get: function () {
return this.dialogVisible;
},
set: function (val) {
this.$emit('update:toggle', val);
}
}
},
}
这样就可以很简单的控制mixin的显示与隐藏啦!(具体有参考juejin:漓漾li)