前言
vue中的组件通信是必不可少的使用场景,回顾了平时使用vue中碰到的一些业务场景和对应采用的组件通信方式,简单地做了一个归类总结,大致有以下一些通信方式:
props/$emit
定义
最常用的父子组件通信方式,父组件通过props向子组件传值,子组件通过$emit事件向父组件触发事件并传值
实例说明
//父组件
<parent :name="xxx" @updateFromChild="xxx"></parent>
//子组件
props: {
name: {
type: String,
default: ''
}
}
methods: {
xxx () {
this.$emit('updateFromChild', xx)
}
}
$attrs 和 \$listeners
$attrs:
定义
子组件中获取除了在props中定义之外的父组件中传递的属性值(class 和 style 除外)
实例说明
//父组件
<parent name="小明" age=5 sex="男" home="杭州" class="parent"></parent>
//子组件
<script>
props: {
name: {
type: String,
default: ''
}
}
mounted () {
console.log(this.$attrs)
// {age:5, sex:"男", home:"杭州"}
}
</script>
使用场景
当孙组件中需要用到爷组件中的大量属性,但是父组件却不需要用到很多,只是作为一个中转的传递,巧用$attrs可以节省在父组件中写的props值。
//父组件
<parent name="小明" age=5 sex="男" home="杭州" class="parent"></parent>
//子组件
<template>
<grand-son :passAttr="$attrs"></grand-son>
</template>
props: {
name: {
type: String,
default: ''
}
}
$listener:
定义
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。
实例说明
//父组件
<parent @change="onChange" @hide="OnHide"></parent>
//子组件
<script>
mounted () {
console.log(this.$listener)
// {change:f, hide:f}
}
</script>
使用场景
子组件中调用父组件的方法
provide 和 inject
provide:
是一个对象或返回一个对象的函数。该对象包含可注入其子孙的属性
inject:
是一个数组或者对象,包含祖先组件中注入的属性
实例说明:
//父组件:
<script>
provide: {
name: '小明',
sayName () {
console.log('我是' + this.name)
}
}
mounted() {
this.name = '小花'
}
</script>
//子组件
<script>
inject:['name', 'sayName'],
mounted () {
console.log(this.name); //小明
this.sayName() //我是小明
}
</script>
可以看到在子组件中的 mounted 中打印出了 inject 中传递进来的 name 属性,并成功执行了 sayName 方法。而且 name 属性值还是'小明',并没有变成'小花',并不是响应式的。
注意点
- provide 和 inject 成对出现使用
- provide 注入的属性,在组件下的所有子孙组件中都能在 inject 中拿到
- provide 和 inject 绑定并不是可响应的,这是和props的本质区别
$parent 和 \$children
定义:
已创建的实例的父实例和子实例中,子实例可以用 this.\$parent 访问父实例,子实例被推入父实例的 \$children 数组中,父实例可以用 this.$children 访问子实例。
实例说明
//父组件
mounted(){
console.log(this.$children)
//可以操作子组件的data,或者调用其methods中的方法
}
//子组件
mounted(){
console.log(this.$parent) //可以拿到父组件中的属性和方法
}
注意点
- \$children和$parent不是响应式的
- Vue官方有说明节制地使用 \$parent 和 $children - 它们的主要目的是作为访问组件的应急方法。
$refs
定义
一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。通过this.$refs.xxx 可以拿到 xxx 子组件中的data和methods。
实例说明
//父组件
<child ref="child"></child>
mounted(){
this.$refs.child.sayHello() // hello
}
//子组件
methods: {
sayHello () {
console.log('hello')
}
}
注意点
- this.$refs.xxx 必须在 xxx 组件渲染完成之后才能拿到,并不是所有生命周期中都能取到。
-
通过 this.$refs.xxx 进行对子组件的属性操作并不是响应式的,因此避免在computed中进行使用。这是一个很好的应急手段,常用于以下两种使用场景
- 父组件直接调用子组件中的方法,节省不必要的代码重写
- 用来取代JQuery或者JS原生方法对dom元素的获取
vuex
不多说,强大的复杂单页面全局数据通信管理中心,供页面中的每个组件进行全局数据的操作,并响应式到各个组件中。如果不知道自行搜索。这里就简单说两个注意点
- 注意vuex的使用场景,不要滥用,复杂的页面数据管理,如果只是简单的数据通信用props和$emit即可,不要为了用而用,适合的才是最好的
- vuex中可以根据情况进行分模块管理,代码的可维护性会得到进一步提升
eventBus
定义
对于非父子组件来说,可以采用一个中间介质来作为一个中央事件总线,完成事件的触发和监听,并进行传值。
实例说明
第一步:创建事件总线:建立一个eventBus.js文件
//仅仅是为了创建一个vue实例
import Vue from 'vue'
export default new Vue()
第二步:在传值的源头组件中引进事件总线,进行事件的触发和传值
<template>
<div class = "source">
<button @click="emitEvent">
</div>
</template>
<script>
import eventBus from './eventBus.js'
export default {
methods: {
emitEvent: funciton () {
eventBus.$emit('sendVal',param)
}
}
}
</script>
第三步:在传值的目标组件中引进事件总线,进行事件的监听和传值的接收
<template>
</template>
<script>
import eventBus from './eventBus.js'
export default {
data: function () {
return {
requireVal: ''
}
}
mounted: function () {
var that = this
eventBus.$on('sendVal',function(val){
that.requireVal = val
})
}
}
</script>
总结如下:
1.创建一个事件总线,例如demo中的eventBus,用它作为通信桥梁
2.在需要传值的组件中用bus.$emit触发一个自定义事件,并传递参数
3.在需要接收数据的组件中用bus.$on监听自定义事件,并在回调函数中处理传递过来的参数
注意点
- eventBus 特别适合非跨多个层级组件之间的通信,解决了通过层层props传递的繁琐,也避免了使用vuex的相对臃肿。
- 缺陷在于如果不加说明和规范管理,容易找不到事件的触发者和监听者。因此建议放在单独的js文件中创建好eventBus的vue实例,并在该文件中注释好事件的触发组件和监听组件。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。