vue 解决兄弟组件、跨组件深层次的通信操作


Posted in Javascript onJuly 27, 2020

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

借助父级组件链式交互

使子组件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 模块的运行机制已经有了一个讲解,当模块内部发生变化的时候,引入模块的部分同样会发生变化,当又一个额外的实例对加载机制进行引入进行emit与emit与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 就可以监听到这个事件并执行回调。

跨组件深层次交互

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

vue 解决兄弟组件、跨组件深层次的通信操作

我们可以实现 子组件之间的交互, 但是如果我们遇到这种情况呢?

vue 解决兄弟组件、跨组件深层次的通信操作

孙组件需要跟子组件3 进行交互,还是使用上述的方法可以做到吗? 答案是肯定的,只要能够使用同一个中央仓库,那么不管什么层级的组件复杂度,都是可以实现两者的交互的。

补充知识:Vue组件跨层级通信

正常组件间通信

父->子组件 是通过属性传递

子->父组件 是通过this.$emit()传递

this.$emit()返回的是this,如果需要一些值 可使用callback方式传递

provide 和 inject

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,

不论组件层次有多深,并在起上下游关系成立的时间里始终生效。

provide 和 inject 绑定并不是可响应的。这是刻意为之的。

然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

provide提供数据,多层子组件 向上层寻找,只要找到 就不在向上层寻找了.

inject 向子组件注入数据

使用方式

第一种方式(传递对象,使用字符串数组接收)

// 父级组件提供 'foo'
var Provider = {
 provide: {
  foo: 'bar'
 },
 // ...
}

// 子组件注入 'foo'
var Child = {
 inject: ['foo'],
 created () {
  console.log(this.foo) // => "bar"
 }
 // ...
}

第二种方式(传递返回对象的函数, 使用对象接收)

provide() {
 return {
  // 2.6.0 版本之前 通常传递this. 但这样的话 会传递很多用不到的属性
  theme: {
   color: 'xxx' //如果传入可响应的数据,这里的属性还是可响应的
  }
 };
}
inject: {
 //这里可以换成其它名字
 theme: {
  from: "theme", // 数据来源
  default: () => ({}) //降级情况下使用的 value
  //可以是 普通值
  //可以是 对非原始值使用一个工厂方法
 }
}
//正常子组件
this.theme //即可访问
//子组件是函数式组件的使用方式
injections.theme.color

Vue.observable( object )

让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象。

可以作为最小化的跨组件状态存储器,用于简单的场景

提供数据可改为

provide() {
 //这时提供的theme 则为可响应的数据
 this.theme = Vue.observable({
  color: "blue"
 });
 return {
  theme: this.theme
 };
},

以上这篇vue 解决兄弟组件、跨组件深层次的通信操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery 学习笔记 选择器之三
Jul 23 Javascript
jQuery对表单的操作代码集合
Apr 06 Javascript
JS判断、校验MAC地址的2个实例
May 05 Javascript
jQuery监控文本框事件并作相应处理的方法
Apr 16 Javascript
JavaScript中用于生成随机数的Math.random()方法
Jun 15 Javascript
一不小心就做错的JS闭包面试题
Nov 25 Javascript
vue.js入门教程之绑定class和style样式
Sep 02 Javascript
JS定时器实现数值从0到10来回变化
Dec 09 Javascript
Javascript Promise用法详解
May 10 Javascript
浅谈Angular7 项目开发总结
Dec 19 Javascript
javascript二维数组和对象的深拷贝与浅拷贝实例分析
Oct 26 Javascript
JS数组方法reverse()用法实例分析
Jan 18 Javascript
vue中组件通信详解(父子组件, 爷孙组件, 兄弟组件)
Jul 27 #Javascript
JS的时间格式化和时间戳转换函数示例详解
Jul 27 #Javascript
vue双击事件2.0事件监听(点击-双击-鼠标事件)和事件修饰符操作
Jul 27 #Javascript
vue键盘事件点击事件加native操作
Jul 27 #Javascript
Element Cascader 级联选择器的使用示例
Jul 27 #Javascript
vue 通过绑定事件获取当前行的id操作
Jul 27 #Javascript
Element Rate 评分的使用方法
Jul 27 #Javascript
You might like
PHP 学习路线与时间表
2010/02/21 PHP
PHP开发中的错误收集,不定期更新。
2011/02/03 PHP
yii框架源码分析之创建controller代码
2011/06/28 PHP
详解PHP字符串替换str_replace()函数四种用法
2017/10/13 PHP
Javascript实例教程(19) 使用HoTMetal(4)
2006/12/23 Javascript
Javascript和HTML5利用canvas构建Web五子棋游戏实现算法
2013/07/17 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
JavaScript实现找出数组中最长的连续数字序列
2014/09/03 Javascript
jquery插件jSignature实现手动签名
2015/05/04 Javascript
jQuery+HTML5实现手机摇一摇换衣特效
2015/06/05 Javascript
第三章之Bootstrap 表格与按钮功能
2016/04/25 Javascript
JS Canvas定时器模拟动态加载动画
2016/09/17 Javascript
jQuery Validate设置onkeyup验证的实例代码
2016/12/09 Javascript
jQuery插件jqGrid动态获取列和列字段的方法
2017/03/03 Javascript
微信小程序商城项目之购物数量加减(3)
2017/04/17 Javascript
页面缩放兼容性处理方法(zoom,Firefox火狐浏览器)
2017/08/29 Javascript
初探Vue3.0 中的一大亮点Proxy的使用
2018/12/06 Javascript
vue模块拖拽实现示例代码
2019/03/09 Javascript
JavaScript实现页面中录音功能的方法
2019/06/04 Javascript
Vue 实现从文件中获取文本信息的方法详解
2019/10/16 Javascript
vue 使用v-for进行循环的实例代码详解
2020/02/19 Javascript
Python之日期与时间处理模块(date和datetime)
2017/02/16 Python
Python Pandas批量读取csv文件到dataframe的方法
2018/10/08 Python
利用Pycharm断点调试Python程序的方法
2018/11/29 Python
python3+selenium实现126邮箱登陆并发送邮件功能
2019/01/23 Python
Python Django的安装配置教程图文详解
2019/07/17 Python
浅谈Html5移动端ios/Android兼容性总结
2018/06/01 HTML / CSS
Dower & Hall官网:英国小众轻奢珠宝品牌
2019/01/31 全球购物
市场营销管理制度
2014/01/29 职场文书
2014年度党员自我评议
2014/09/13 职场文书
公司领导班子四风对照检查材料
2014/09/27 职场文书
具结保证书
2015/01/17 职场文书
团委工作总结2015
2015/04/02 职场文书
信用卡催款律师函
2015/05/27 职场文书
开天辟地观后感
2015/06/09 职场文书
Valheim服务器 Mod修改安装教程 【ValheimPlus】
2022/12/24 Servers