在使用Vue进行组件开发时,对于父组件传递过来的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: "xxx"
在Vue2.X中,传入的props属性是不允许改变的,因为在新的渲染机制中,每当父组件重新渲染时,子组件都会被重新覆盖,所以props属性,在子组件内部应该被看做是不可变对象。所以我们必须借助中间变量来做缓冲,通过中间变量的改变发送事件给父组件,父组件接收到后,再对props进行更改。
在实现公司内部组件时,我引用了element-ui的Dialog组件,为了方便组件的复用,我将一些基础属性封装在了一个自定义组件中,大致的结构如下:
为了控制弹出框的显示情况,所以我定义了一个Visible
属性,
Visible
的流向是:
在element-ui组件中 ,控制显示的一般会加上这个属性:visible.sync="visible"
这个意思是说elementui组件在内部改变visible
之后会通知父组件visible
属性更新了。它的变化会回传给父组件,所以当时在自定义组件中拿到这个值就对其进行操作,发现报错了。此时的数据流向如下:
这个属性是Index传进来的,所以我们没有经过Index,在自定义组件就对其进行了修改,所以不符合Vue对于属性数据单向传递的规则,正确的做法是像这样:
但是由于elementUI直接就将变化给回传了,所以我们不能直接传给Index组件,需要借助一个中间变量来接受这个值,然后把这个变化回传给Index组件,告诉Index自定义组件需要更新。
首先我们顶一下Index组件需要传的值:
<user-dialog :showDialog.sync="dialogTableVisible" :ruleForm="ruleForm" v-if="dialogTableVisible"
@closeDialog="closeUserDialog"></user-dialog>
dialogTableVisible
属性传入到user-dialog
自定义的组件中
自定义的组件
props: {
showDialog: {
type: Boolean,
default: false
}
},
data(){
return {
//show控制elementui的变化
show: false,
}
}
//创建时,赋值
created() {
this.show = this.showDialog;
},
我们借助show
作为中转变量,当show发生变化时,我们发送事件给Index组件
所以,在关闭elementui时,触发一个回调函数:
closeDialog() {
this.show = false;
this.$emit('closeDialog');
},
父组件可以通过监听这个事件来关闭自定义组件:
<user-dialog :showDialog.sync="dialogTableVisible" :ruleForm="ruleForm" v-if="dialogTableVisible"
@closeDialog="closeUserDialog"></user-dialog>
事件方法:
closeUserDialog() {
this.dialogTableVisible = false;
},
通过事件Bus来传递事件
import Vue from 'vue'
const Bus = new Vue()
var app= new Vue({
el:'#app',
data:{
Bus
}
})
直接创建一个空Vue实例,作为消息总线承载体,然后在子组件中通过
this.$root.Bus.$on()
,this.$root.Bus.$emit()
来调用.
不需要走props,子组件改变就调用$emit('xxx')
发送事件
父组件只需要监听$on('xxx')
然后操作传入的属性值即可。