Vue组件间的通信 ☎️

5,973 阅读4分钟

人之间的感情是复杂的以及需要维护的,那么就免不得各种打电话

你有多久没有打电话了呢?

你又有多久没有收到电话了呢?

你还记得你的手机来电铃声吗????

爸爸给儿子打电话 ☎️

父组件通过使用v-bind变量来实现数据的传入

// 父组件
<Child :name="name" :clickFn="handleClick"/>

子组件通过实现options上面的props来接受父组件传递过来的数据

props接受约束数据,下面罗列了四种方式:

// 方式1:直接传递变量名,不做任何的类型约束以及值约束
props:['name','handleClick']


// 方式2:传递变量名 + 类型的约束
props:{
  name: String,
  handleClick: Function
}

// 方式3 :传递变量名 + 多个类型的约束
props:{
  name: [String, Number]
}

// 方式4:传递变量名 + 类型的约束 + 默认值
props:{ 
  name:{
    type:String,
    default: 'zhangshan'
  },
  handleClick:{
     type: Function,
     default: ()=>{}
  }
}

并且为了保证单行数据流,不会造成其他子组件使用到父组件传递过来的数据的异常,要求子组件是不能够修改props的数据的值(程序也会通过报错来告知我们)。

儿子给爸爸打电话 ☎️

vue的原型上实现了$emit的方法,用来做事件的发送

子组件会通过$emit发送事件给父组件,父组件通过v-on的形式来监听子组件发送来的事件

// 子组件
<button @click="$emit('onChildClick')">click me </button>

// 父组件
<Child @onChildClick=“onChildClick”/>

如果需要传递参数,可以直接在$emit的第二个参数处写入

// 子组件
<button @click="$emit('onChildClick', item)">click me </button>

// 父组件
<Child @onChildClick=“onChildClick”/>

onChildClick(item){
  console.log('我接受到了子组件传递过来的参数啦!', item)
}

爸爸主动拿起了儿子的电话 ☎️

ref是可以设置在子组件标签上面的一个属性,我们可以通过this.$refs.childRef来获取到子组件的实例,从而从实例上面调用子组件的属性或者方法!

<Child ref="childRef"/>

this.$refs.childRef.onChildClick()

除了ref,还可以使用$children来获取到子组件的实例,从而从实例上面调用子组件的属性或者方法!

this.$children[0] // 第一个孩子组件

儿子主动拿起了爸爸的电话 ☎️

在子组件可以通过this.$parent来获取到父组件的实例,从而从实例上面调用子组件的属性或者方法!用法同上。

注:孩子有很多孩子,但是爸爸只有一个

爷爷给孙子打电话 ☎️

爷爷给孙子打电话有点累,爷爷不知道孙子的电话号码,于是发现只有必须先打给爸爸,爸爸再打给孙子!😢

爷爷说话又很慢,只能一个词一个词的说,

爷爷组件将参数一层一层原封不动的传递下去

// 爷爷
<Parent :name="name" :age="age" :gender=“gender”/>

// 父亲
<Child :name="name" :age="age" :gender=“gender”/>
props:['name', 'age', 'gender']

// 孙子
<div>{{name}} - {{age}} - {{gender}}</div>
props:['name', 'age', 'gender']

孙女羊羊🐑是我们家最聪明可爱的小萝莉!

羊羊看不下去了,于是找了个录音笔,把爷爷说的所有词录下来,然后把录音笔发给爸爸:

v-bind="$props" 传递全部的props,稍微减轻了一点工作量

// 爷爷
<Parent :name="name" :age="age" :gender=gender/>

// 爸爸 props接受 && props一起传
<Child v-bind="$props"/>
props:['name', 'age', 'gender']

// 儿子 props接受
<div>{{name}} - {{age}} - {{gender}}</div>
props:['name', 'age', 'gender']

但是发现爸爸需要把录音笔里面的所有词都全部拆解出来,再一个一个的传递给儿子,

羊羊看不下去了,告诉爸爸,你不需要听录音笔里面的词再告诉你儿子,你只需要把爷爷的这个录音笔直接给儿子啊!

v-bind="$attrs"的其中一个功能是可以实现传递不在props里面的值,

父组件既不需要接受爷爷组件传递下来的一个一个的参数,也不需要一个一个的参数再传递下去给子组件!

// 爷爷
<Parent :name="name" :age="age" :gender=gender/>

// 父亲
<Child v-bind="$attrs"/>

// 儿子 props接受
<div>{{name}} - {{age}} - {{gender}}</div>
props:['name', 'age', 'gender']
// 儿子 props 不接受
<div>{{$attrs.name}} - {{$attrs.age}} - {{$attrs.gender}}</div>

孙子给爷爷打电话 ☎️

孙子先把电话$emit('onChildClick')打给了爸爸,爸爸拆解了孙子要说的话,再打电话给爷爷@onChildClick="$emit('onChildClick')"

// 儿子
<button @click="$emit('onChildClick')" @click="$emit('onChildClick1')">click me </button>

// 爸爸
<Child @onChildClick="$emit('onChildClick')"  @onChildClick1="$emit('onChildClick1')"/>

// 爷爷
<Parent @onChildClick="console.log('我终于收到了孙子辈的点击事件了!')"  @onChildClick1="console.log('我终于收到了孙子辈的点击事件了1!')"/>

羊羊说爸爸你直接把电话转接到爷爷那里去吧!你干嘛要偷听别人通话!

v-on="$listeners"可以实现事件的打包📦

// 儿子
<button @click="$emit('onChildClick')">click me </button>

// 爸爸
<Child v-on=“$listeners”/>
  
// 爷爷
<Parent @onChildClick="console.log('我终于收到了孙子辈的点击事件了!')"/>

秦始皇(老祖宗)给我打电话 ☎️

当我们的组件层级更深的时候,A -> B -> C -> D -> E -> F ,上面的方法都显得不太适用了,我们可以使用 provide & inject 来实现跨层级的数据传递。

父组件只要声明了provide,在其子组件,孙组件,曾孙组件等能形成上下游关系的组件中交互,无论多深都能通过inject来访问provider中的数据。

// 最上面的组件 elForm
provide(){
   return {elForm:this}  
}

// 最下面的组件 elFormItem
inject:['elForm']

(葫芦娃)水娃给火娃打电话 ☎️

比较累的做法:props + emit + on

兄弟1组件emit -> 父组件on -> 兄弟2组件props

期望做法:兄弟1组件emit事件,兄弟2组件on事件

event bus

全局EventBus,虽然在某些示例中不提倡使用,但它是一种非常漂亮且简单的方法,可以跨组件之间共享数据。

1.定义一个空的Vue实例,作为中央事件总线。

2.A组件定义方法去触发自定义事件

3.B组件在钩子里面去监听

var EventBus = new Vue();

this.$bus.$emit('call',{...});

this.$bus.$on('call',($event) => {...})

vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

export default new Vuex.Store({
  state: {
    userInfo:{}
  },
  mutations: { // commit
    updateUserInfo (state,Object) {
       state.userInfo= Object
    }
  },
  actions: { // dispatch 副作用
    getUserInfo(context){
    		// 1.发送http请求,拿到用户信息数据
    		const userInfo = http()
    		
    		// 2.通过commit发送mutation里面的方法修改state
    		context.commit('updateUserInfo', userInfo)
    }
  },
  getters:{
    userInfo: state.userInfo
  }
})

总结

组件间的通信方式有很多种:

  1. props实现数据的向下传递

  2. emitandemit and on实现数据的发布与监听

  3. ref,ref, parent, $children可以获取到组件的实例

  4. props,props, attrs, $listeners可以实现数据/事件的打包📦运输

  5. eventbus and vuex可以实现跨组件的通信

以及还有一些没有写出来的通信方式...

最后

最后,本篇也是一篇征友文,快来给我打电话吧!☎️