问题描述
最近在做一个小功能,点击一个按钮,进入二级页面。
于是想到vue的父子组件之间可以传值,这样只需要在父组件定义一个控制子组件是否显示的变量然后传给子组件,然后就是某些操作后实时的更新这个变量的值就好了。
父组件给子组件传值一切顺利,本以为很快就搞定,但是最后还是出问题了,被现实给了一个大比斗😭。
不过好在经过一番努力找了问题原因并成功解决了
,接下来跟大家分享一下本次的踩坑。
错误示例
代码(片段)
父组件调用子组件,并传值
<!-- objectVisible用来判断是否显示子组件-->
<linee :visible.sync="objectVisible" @closeDialog="closeDialog"></linee>
methods: {
openDialog() { // 打开子组件
this.$set(this, 'objectVisible', true)
},
closeDialog() {// 关闭子组件
this.$set(this, 'objectVisible', false)
}
}
子组件引用父组件的值
<!-- 引用父组件传过来的objectVisible用来判断是否显示子组件-->
<el-dialog :visible.sync="objectVisible" top="23vh" width="600px" :close-on-click-modal="false" @close="close">
</el-dialog>
// 接受父组件的传值
props: {
objectVisible: {
type: Boolean,
default: false
}
}
methods: {
close() { // 关闭子组件时,修改父组件的值,不然下次就无法打开了
this.$emit('closeDialog') // 调用父组件的方法(第一种方式)
}
}
错误信息如下
当点击关闭按钮,关闭组件时,控制台报出如下错误: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”。如下图所示。
原因
查阅了一番资料之后,找到了报错的原因。
1、所有的prop都使得其父子prop之间形成了一个单向下行绑定:父级prop的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
2、每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变prop。
正确示例
代码(片段)
父组件调用子组件,并传值
<!-- objectVisible用来判断是否显示子组件-->
<linee :visible.sync="objectVisible" @closeDialog="closeDialog"></linee>
methods: {
openDialog() { // 打开子组件
this.$set(this, 'objectVisible', true)
},
closeDialog() {// 关闭子组件
this.$set(this, 'objectVisible', false)
}
}
子组件引用父组件的值
<!-- 不直接使用父组件传过来的objectVisible,而使用自己定义的isShowPage用来判断是否显示子组件-->
<el-dialog :visible.sync="isShowPage" top="23vh" width="600px" :close-on-click-modal="false" @close="close">
</el-dialog>
watch: {
objectVisible(val) {
this.isShowPage = val // 新增objectVisible的watch,监听变更并同步到isShowPage上
}
},
data() {
return {
// 定义一个isShowPage,将objectVisible的值赋予isShowPage
isShowPage: this.objectVisible
}
},
// 接受父组件的传值
props: {
objectVisible: {
type: Boolean,
default: false
}
}
methods: {
close() { // 关闭子组件时,修改父组件的值,不然下次就无法打开了
this.$emit('closeDialog') // 调用父组件的方法(第一种方式)
}
}
子组件修改父组件值方式
上述代码中使用的是一种(this.$emit
)子组件修改父组件的方式,在查阅资料的过程中还学习到了另一种方式,就是this.$parent
。
下面简单介绍一下这两种方式。
this.$emit
这种方式需要在父组件中自定义一个方法,然后传递给子组件,子组件通过this.$emit调用父组件中的方法,实现父子组件通信。子组件触发事件,父组件监听事件。
代码
代码在上文中,就不赘述了。
this.$parent
子组件直接修改或者触发父组件事件,无需进行方法的传递、接收,以及监听事件的定义。
代码
父组件中的代码
data() {
return {
num: 0
}
},
methods: {
close() {
this.$set(this, 'selectObjectVisible', false)
}
}
子组件修改父组件变量的值,调用父组件的方法
methods: {
test() {
this.$parent.num = 2 // 修改父组件的变量的值
this.$parent.close() // 调用父组件的方法
}
}
本次就分享这些,希望能帮到更多的人!😃