vue 解决兄弟组件、跨组件深层次的通信问题

兄弟组件之间的通信同样是在项目中经常会遇到的组件间的通信问题之一, 这种问题的最根本方法就是: 把兄弟组件内部的变量提升到一个中央仓库。

借助父级组件链式交互

使子组件1 通过 $emit 通知父级, 父级再通过响应 子组件1 的事件去触发子组件2的事件,这样的链式操作,在子组件不多的时候,但是一个不错的解决方法

子组件1

<template>
  <div>
    <p @click="$emit('fromFirst','来自A组件')">first组件</p>
  </div>
</template>

<script>
  export default {
    name: 'first'
  }
</script>

子组件2

<template>
    子组件2
  <div>{{secondInfo}}</div>
</template>

<script>
export default {
    name: 'second', 
    data() {
        return {
            this.secondInfo: null
        }
    },
  created(){
      this.$on('fromFather', (info) => {
          this.secondInfo = info
      })
  }
}
</script>

父组件

<template>
  <first @fromFirst='handleFromFirst' />
  <second ref='second' /> 
</template>

<script>
import First from './first'
import Scond from './second'
export default {
    components: {First, Second},
    data() {
        return {
            this.secondInfo: null
        }
    },
    methods:{
        handleFromFirst(val) {
            let second = this.$refs.second
            second.$emit('fromFather', val)
        }
    }
}
</script>

子组件1 触发父组件的 fromFirst 事件, 在事件中又触发了子组件2的 fromFather事件,并将从子组件1 传递过来的参数传递给了该事件, 当子组件2 执行该事件的时候,将内部的 secondInfo 改变。这就实现了一个兄弟组件的交互。

这个方式在 react 里面同样也是适用的, 但是如果父组件内包含了多个子组件并包含了复杂的逻辑, 有没有更好的方式来解决这种方式呢。

大部分第一个想到的是 vuex, 当然这在一个业务逻辑、数据复杂的项目中是一个很好的解决方法, 但是想象我们要编写一个通用组件,这个组件可能被用到不同的项目中来, 如果使用 vuex 这就要求每一个使用这个组件的项目中都要使用 vuex, 这显然是不好的。

借助中间文件,充当中央仓库

还好 ES6 的模块机制天然就支持建立一个中央仓库, 当 A 文件使用 import value from './b.js' 来引用 B 文件里面的 value 的时候, 这时就会赋值给 A 文件一个 B 文件的 value只读引用, 当 B 文件里面的 value 的值发生变化的时候, A 文件里面的 value 也会跟着改变。

// lib.js
export let counter = 3;
export function incCounter() {
counter++;
}

// main.js
import { counter, incCounter } from './lib';
console.log(counter); // 3
incCounter();
console.log(counter); // 4

定义一个额外的实例进行一个事件的中转,对于ES6 模块的运行机制已经有了一个讲解,当模块内部发生变化的时候,引入模块的部分同样会发生变化,当又一个额外的实例对加载机制进行引入进行 e m i t emit与 on进行绑定通信,能轻而易举解决问题,通过b->a->c的模式直接过渡。

解决 vue 兄弟组件之间的通信我们同样也可以使用中央仓库的方式来实现。

// store.js 作为中央仓库

import Vue from 'vue'
export default new Vue()

通过 new 一个 vue 的实例当作兄弟组件交互的中央仓库。

父级组件

<template>
  <first/>
  <second/> 
</template>

<script>
import First from './first'
import Scond from './second'
export default {
    components: {First, Second}
}
</script>

父组件只是引入子组件, 不再作为中央仓库来过渡交互。

子组件1

<template>
    <div @click='hanleClick'>子组件1</div>
</template>

<script>
import Store from './store'

export default {
    name: 'first',
    methods: {
        handleClick() {
            Store.$emit('fromFirst', '来自子组件1的传值')
        }
    }
}
</script>

因为我们的目的就是把 Store 作为一个中央仓库,这里我们把 fromFirst 事件添加到了 Store 上面而不是当前组件 this 上。

子组件2

<template>
    子组件2
  <div>{{secondInfo}}</div>
</template>

<script>
import Store from './store'
export default {
    name: 'second', 
    data() {
        return {
            this.secondInfo: null
        }
    },
  created(){
      Store.$on('fromFirst', (info) => {
          this.secondInfo = info
      })
  }
}
</script>

子组件2 里面同样也是使用 Store 实例来监听 fromFirst 事件, 因为子组件1和子组件2里面添加事件和监听事件的是同一个实例,根据我们在上文中分析的 ES6 中的情况, 当 Store 添加了 fromFirst 这个时间之后, Store实例的 $on 就可以监听到这个事件并执行回调。

跨组件深层次交互

上面讲的组件之间的关系是这样的:

在这里插入图片描述

我们可以实现 子组件之间的交互, 但是如果我们遇到这种情况呢?
在这里插入图片描述
孙组件需要跟子组件3 进行交互,还是使用上述的方法可以做到吗? 答案是肯定的,只要能够使用同一个中央仓库,那么不管什么层级的组件复杂度,都是可以实现两者的交互的。

猜你喜欢

转载自blog.csdn.net/starleejay/article/details/83660494
今日推荐