数据通信的4种方式:绑定引用类型(Object地址)、emit自定义事件、全局eventHub、Vuex
父子组件通信
爷孙组件通信
兄弟组件通信更新
最新文档中提出,可以使用$root来访问根实例的数据
数据通信的方式
- 引用类型数据:v-bind引用data里的数据
- 自定义事件:子组件
emit
一个自定义事件,父组件监听这个自定义事件 - 全局事件:eventHub
- 状态管理:Vuex
引用类型数据
当引用的类型是对象(Object)时,由于引用的是对象的内存地址,因此,当子组件修改数据时,父组件也会跟着修改(因为他们指向同一个地址)
|
|
父组件的obj和子组件的obj2指向同一个内存地址,因此,当子组件的obj2修改数据时,父组件的obj也会跟着修改
为了避免子组件修改数据时对父组件的影响,需要对Object类型的数据进行深拷贝
父子组件通信
父传子通过props
父组件使用 props 传递数据给子组件
|
|
Prop验证
props一般写成数组的形式props:['name','age','content']
,如果要为props指定验证要求,则写成对象的形式
$parent访问父组件实例
$parent
属性可以让子组件访问父组件的实例。它可以直接触达父组件,以替代将数据以 props
的方式传入子组件。这种直接获取父组件数据的方式不推荐使用,因为这会使得你的应用更难调试和理解。
子传父
父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
- 使用 $on(eventName) 监听事件
- 使用 $emit(eventName) 触发事件
子组件无法直接修改父组件的数据,必须通过$emit()通知父组件,让父组件修改父组件的数据
如果这个事件处理函数是一个方法:
那么组件$emit 发出的第一个参数 将会作为该方法的第一个参数:
另一个例子
【点击查看例子】
一个简单的TodoList
【点击查看例子】
$refs访问子组件实例
你可以通过 ref
特性为每个子组件赋予一个唯一的ID
引用,然后就能直接访问每个子组件实例了。这种直接获取子组件数据的方式不推荐使用,因为这会使得你的应用更难调试和理解。
|
|
在HTML中通过$event获取参数
如果这个事件处理函数不在methods里,而是在HTML中。那么通过$event获取$emit 发出的第一个参数
|
|
在HTML中,父级通过 $event 访问到$emit发出的第一个参数
组件绑定原生事件
在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native
修饰符:
.sync 修饰符
文档:sync修饰符
在有些情况下,我们可能需要对一个 prop 进行“双向绑定”,使子组件的prop修改时,父组件的data也跟着改变。为了方便起见,我们为这种模式提供一个缩写,即 .sync
修饰符,其实它是v-on:update
的语法糖
|
|
上面的代码用.sync
语法糖改写如下:
爷孙通信
- 爷孙之间无法直接通信
- 爷爷必须先通过props将数据传给父组件,然后靠父组件将数据传给孙组件
- 孙组件必须先通过$emit通知父组件,然后靠父组件将数据传回给爷组件
|
|
|
|
兄弟组件通信(利用事件总线)
利用eventHub(也叫eventBus)实现兄弟组件通信
通过使用事件中心,允许组件自由交流,无论组件处于组件树的哪一层。由于 Vue 实例实现了一个事件分发接口,你可以通过实例化一个空的 Vue 实例来实现这个目的。
目前事件总线是解决兄弟间通信,祖父祖孙间通信的最佳方法
- 一个组件通过
bus.$emit('自定义事件名',参数)
来发布事件 - 另一个组件在
created
阶段,监听bus.$on('自定义事件名',(参数) = >{ 执行代码 })
|
|
|
|
改进
为了避免全局变量,将eventHub放到Vue的原型上
https://blog.csdn.net/a5534789/article/details/53415201
https://juejin.im/entry/59828fdd6fb9a03c5754b8ab
Object.defineProperty(Vue.prototype, ‘$axios’, { value: axios })
另一个例子
【点击查看例子】
再看一个例子
|
|
|
|
eventHub
|
|
|
|
|
|
$root访问根组件实例
为什么要弄个 Bus?直接 this.$root.$on、this.$root.$emit 不更简单粗暴?
答:按照文档上的说法是专门用一个空的 Vue 实例(Bus)来做中央事件总线更加清晰也易于管理。
掘金:非父子组件通信方法
文档:$root
在每个 new Vue 实例的子组件中,其根实例可以通过 $root 属性进行访问。例如,在这个根实例中:
所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。
在组件上使用 v-model
|
|
为了让它正常工作,这个组件内的 input
必须:
- props: [‘value’]
- $emit(‘input’, $event.target.value)
|
|
在非表单控件的组件上也能用v-model
v-model本质上是个语法糖,它与value
绑定,并监听input
事件。因此,只要满足以下条件,就能在非表单控件上使用v-model
- props:[‘value’]
- this.$emit(‘input’,参数)
|
|
|
|
Vuex进行状态管理
对于大多数复杂情况,更推荐使用一个专用的状态管理层:Vuex。
小技巧
自定义事件名
https://cn.vuejs.org/v2/guide/components-custom-events.html#%E4%BA%8B%E4%BB%B6%E5%90%8D
自定义事件始终使用 kebab-case 的事件名【跟组件和 prop 不同,事件名不会自动进行大小写转换。】
绑定多个事件
|
|
组件绑定原生事件
在 Vue 2.0 中,为自定义组件绑定原生事件必须使用 .native
修饰符:
$emit()中的事件名称始终用kebab-case
|
|
|
|