前言

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中进行使用。这是一个很好的应急手段,常用于以下两种使用场景

    1. 父组件直接调用子组件中的方法,节省不必要的代码重写
    2. 用来取代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实例,并在该文件中注释好事件的触发组件和监听组件。

款冬
1.5k 声望42 粉丝

前端小小弄潮儿~


« 上一篇
vue数据渲染
下一篇 »
koa源码解读