Vue组件通信时遇到的问题

272 阅读2分钟

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修饰符用来实现数据的双向绑定(其实就是emitemit 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)
  }
}
...