1.子组件的props是array、object时改变props为什么不报错? ** 之前的一个操作很让我郁闷,当子组件接受到的props是简单数据类型时,再尝试对他的值进行修改,vue就会报错,违背了单向数据流的思想,但是如果props是对象或者数组这种引用类型的话,子组件修改的时候不会报错,而且父组件的值也会改变。
第一反应是vue在对props传值时只能监听到简单数据类型,当值发生变动时就会报错,引用类型的监听不到,所以不报错。
但事实似乎不是这样,经过一番了解,问题的原因其实就是数据类型的问题。对于数组和对象这种引用数据类型,传递到子组件的其实是一个引用,当对props的值进行修改时,只是修改了这个引用,指向的内存地址是没有变的,但是这种修改会影响到父组件中的值。原理可参考es6 const
// const定义的变量不可修改
const obj = { }
obj.a = 1
console.log(obj)
// {a:1}
obj = {a: 1} // 报错(改变了内存地址)
2.使用sync来更新数据 **vue中的父子组件通信一般不允许子组件改动父组件传递过来的props值,但是在有些场景我们必须要这么做,比如做一些文本的编辑等等。所以vue提供了.sync修饰符用来实现数据的双向绑定(其实就是on的用法)。
- 基本数据类型:数据更新时会触发computed的set,所以可以把在这里update
// 父组件
<child :params.sync="'wgj'"></child>
// 子组件
<template>
<input v-model="_params"/>
</template>
export default {
props: {
params: String
},
computed: {
_params: {
get() {
return params
},
set(val) {
this.$emit('update:params', val)
}
}
}
}
- 引用数据类型:前面说了,组件通信的时候其实传到子组件的就是一个引用,在子组件中直接修改的话只是修改的引用,如果这里用computed去触发update的话是触发不了的,因为computed的数据只有在内存地址发生变化的时候才会触发set,所以这里只能使用watch去监听
// 父组件
<child :params.sync="{name: 'wgj'}"></child>
// 子组件
<template>
<input v-model="params.name"/>
</template>
export default {
props: {
params: Object
},
watch: {
'params': {
handler(newVal) {
this.$emit('update:params', newVal)
},
deep: true // 这是关键,vue会遍历对象给每个属性都加个watcher,性能开销大。false的时候只监听第一层
}
}
}
// 如果只监听某个属性的话可以这样写
...
'params.xxx': {
handler(newVal) {
this.$emit('update:params', newVal)
}
}
...