八种Vue组件间通讯方式合集(推荐)


Posted in Javascript onAugust 18, 2020

前言

Vue 提供了各种各样的通讯,其中包括 兄弟间 的通讯和 非兄弟间 的通讯,借此机会做个总结,查阅起来方便。如果喜欢的话可以帮忙点个赞 :+1: 或者关注一下 :yum:

1、props

 目录结构

components
 ├── Parent.vue // 父亲
 ├── Son1.vue  // 儿子1

代码结构

在父亲组件中使用儿子组件,给儿子通过 :date="xxx" 单向传值

<template>
 <div>
 <div>爸爸:{{date}}</div>
 <Son1 :date="date"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
 return {
  date: 1,
 };
 },
};
</script>

儿子组件通过 props 接受父组件传过来的值

<template>
 <div>儿子:{{date}}</div>
</template>
<script>
export default {
 props: {
 date: {
  type: Number, //校验类型
  default: "1",
 },
 },
};
</script>

2、$emit

目录结构

components
 ├── Parent.vue // 父亲
 ├── Son1.vue  // 儿子1

代码结构

子组件通过触自身的方法来触发 $emit 方法,再触发父组件的方法,通过 回调传参 的方式将修改的内容传递给父组件

<template>
 <div>
 <div>儿子:{{date}}</div>
 <button @click="changeNum">修改</button>
 </div>
</template>
<script>
export default {
 props: {
 date: {
  type: Number,
  default: "1",
 },
 },
 methods: {
 changeNum() {
  this.$emit("changeNum", 2);
 },
 },
};
</script>

父组件接受回调 params 参数,即爸爸需要给儿子绑定了一个自定义的事件, $on("changeNum",params)

<template>
 <div>
 <div>爸爸:{{date}}</div>
 <Son1 :date="date" @changeNum="changeNum"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
 return {
  date: 1,
 };
 },
 methods: {
 changeNum(params) {
  this.date = params;
 },
 },
};
</script>

.sync

目录结构

components
 ├── Parent.vue // 父亲
 ├── Son1.vue  // 儿子1

代码结构

子组件通过 $emit("update:xxx") 发射事件

<template>
 <div>
 <div>儿子:{{date}}</div>
 <button @click="changeNum">修改</button>
 </div>
</template>
<script>
export default {
 props: {
 date: {
  type: Number,
  default: "1",
 },
 },
 methods: {
 changeNum() {
  this.$emit("update:date", 2);
 },
 },
};
</script>

父组件通过 :xxx.sync="xxx" 接受参数

<template>
 <div>
 <div>爸爸:{{date}}</div>
 <Son1 :date.sync="date"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
 return {
  date: 1,
 };
 },
};
</script>
<Son1 :date.sync="date"></Son1>
//这个写法是上面的替代品 默认组件内部触发 update:count 规定写法
<Son1 :date="date" @update:date="val=>date=val"></Son1>

v-model

目录结构

components
  ├── Parent.vue  // 父亲
  ├── Son1.vue   // 儿子1

代码结构

子组件触发的事件只能是 input 事件,接收 props 的属性名只能叫 value

<template>
 <div>
  <div>儿子:{{value}}</div>
  <button @click="changeNum">修改</button>
 </div>
</template>
<script>
export default {
 props: {
  value: {
   type: Number,
   default: 1,
  },
 },
 methods: {
  changeNum() {
   this.$emit("input", 2);
  },
 },
};
</script>

父组件通过 v-model 接收参数

<template>
 <div>
  <div>爸爸:{{value}}</div>
  <Son1 v-model="value"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
  return {
   value: 1,
  };
 },
};
</script>
<Son1 :value="value" @input="val=>value=val"></Son1>
//这个写法是上面的替代品 默认组件内部触发 input 规定写法
<Son1 v-model="value"></Son1>

v-model 局限只能传递一个属性 如果只有一个 可以使用 v-model 多个依然需要使用 .sync

3、 $parent和 $children

目录结构

components
  ├── Parent.vue  // 父亲
  ├── Son1.vue   // 儿子1
  ├── Grandson1.vue //孙子1

代码结构

如下场景:孙子想要给爷爷传递数据,孙子需要找到爷爷身上的事件去传递 $parent.$emit

<template>
 <div>
  <div>孙子{{value}}</div>
  <button @click="$parent.$emit('change',3)">修改</button>
 </div>
</template>
<script>
export default {
 props: {
  value: {
   type: Number,
   default: "",
  },
 },
};
</script>

儿子组件使用孙子组件

<template>
 <div>
  <div>儿子:{{value}}</div>
  <grandson1 :value="value"></grandson1>
 </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
 components: {
  grandson1,
 },
 props: {
  value: {
   type: Number,
   default: 1,
  },
 },
};
</script>

爸爸身上给孙子自定义change事件

<template>
 <div>
  <div>爸爸:{{value}}</div>
  <Son1 @change="val=>value=val" :value="value"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
  return {
   value: 1,
  };
 },
};
</script>

如果层级很深那么就会出现 $parent.$parent..... 我们可以封装一个 $dispatch 方法向上进行派发

Vue.prototype.$dispatch = function $dispatch(eventName, data) {
 let parent = this.$parent;
 while (parent) {
  parent.$emit(eventName, data);
  parent = parent.$parent;
 }
};

相同的道理,如果既然能够向上寻找父亲,就能向下寻找儿子,也可以封装一个向下派发的方法 $broadcast

Vue.prototype.$broadcast = function $broadcast(eventName, data) {
 const broadcast = function () {
  this.$children.forEach((child) => {
   child.$emit(eventName, data);
   if (child.$children) {
    $broadcast.call(child, eventName, data);
   }
  });
 };
 broadcast.call(this, eventName, data);
};

4、 $attrs和 $listeners

目录结构

components
  ├── Parent.vue  // 父亲
  ├── Son1.vue   // 儿子1
  ├── Grandson1.vue //孙子1

$attrs 批量向下传入属性

<template>
 <div>
  <div>爸爸:{{value}}</div>
  <Son1 @change="val=>value=val" :value="value"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
  return {
   value: 1,
  };
 },
};
</script>

在儿子组件中使用 $attrs属性,配合 v-bind 可以将属性继续向下传递

<template>
 <div>
  <div>儿子:{{$attrs.value}}</div>
  <grandson1 v-bind="$attrs"></grandson1>
 </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
 components: {
  grandson1,
 },
 mounted() {
  console.log(this.$attrs);
 },
};
</script>

注意一点:在使用 $attrs的时候,如果组件中使用了 props 就会将属性从当前 attrs 移除掉

在孙子组件中使用 $attrs属性,可以将属性继续向下传递

<template>
 <div>
  <div>孙子{{$attrs.value}}</div>
 </div>
</template>
<script>
export default {
 //props: {
 // value: Number,
 //},
 mounted() {
  console.log(this.$attrs);
 },
};
</script>

如果爸爸传递给儿子元素, 儿子有三个属性用不到, 孙子传递给孙子,但是不想在页面上这个属性,可以设置 inheritAttrs: false

$listeners 批量向下传入方法

<template>
 <div>
  <div>爸爸:{{value}}</div>
  <Son1 @click="change" :value="value"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 data() {
  return {
   value: 1,
  };
 },

 methods: {
  change() {
   this.value = 2;
  },
 },
};
</script>

可以在son1组件中使用 $listeners 属性,配合 v-on 可以将方法继续向下传递

<template>
 <div>
  <div>儿子:{{$attrs.value}}</div>
  <grandson1 v-bind="$attrs" v-on="$listeners"></grandson1>
 </div>
</template>
<script>
import grandson1 from "./grandson1";
export default {
 components: {
  grandson1,
 },
 mounted() {
  console.log(this.$attrs);
  console.log(this.$listeners);
 },
};
</script>

孙子组件可以直接使用 $listeners 上的方法

<template>
 <div>
  <div>孙子{{$attrs.value}}</div>
  <button @click="$listeners.click"></button>
 </div>
</template>
<script>
export default {
 mounted() {
  console.log(this.$attrs);
  console.log(this.$listeners);
 },
};
</script>

5、Provide & Inject

目录结构

app.vue
components
  ├── Parent.vue  // 父亲
  ├── Son1.vue   // 儿子1
  ├── Grandson1.vue //孙子1

代码结构

在父级声明一个公共数据

export default {
 provide() {
  return { vm: this };
 },
};

在子组件中可以注入原理,会将数据挂载在当前实例上

<template>
 <div>
  <div>孙子</div>
 </div>
</template>
<script>
export default {
 inject: ["vm"],
 mounted() {
  console.log(this);
 },
};
</script>

八种Vue组件间通讯方式合集(推荐)

注意事项:这个方法使用之后比较混乱,它一般 不会在业务代码中使用 ,经常是在组件库或者多级通信,为了方便你可以使用 provide

6、ref

目录结构

components
  ├── Parent.vue  // 父亲
  ├── Son1.vue   // 儿子1

代码结构

ref 获取的是真实的dom元素,如果放到组件上代表的是 当前组件的实例 。 父组件中可以直接获取子组件的方法或者数据。

<template>
 <div>
  <div>爸爸</div>
  <Son1 ref="son"></Son1>
 </div>
</template>
<script>
import Son1 from "./son1";
export default {
 components: { Son1 },
 mounted() {
  this.$refs.son.show();
 },
};
</script>
<template>
 <div>
  <div>儿子</div>
 </div>
</template>
<script>
export default {
 methods: {
  show() {
   console.log(1);
  },
 },
};
</script>

注意事项: ref 不要 重名 , 但是当且仅当使用 v-for 的时候会导致出现 数组 情况

7、EventBus

目录结构

main.js
components
  ├── Grandson1.vue  // 孙子1
  ├── Son2.vue   // 儿子2

代码结构

EventBus 可用于 跨组件 通知(不复杂的项目可以使用这种方式)

Vue.prototype.$bus = new Vue();

Grandson1组件和Son2相互通信

<template>
 <div>孙子1</div>
</template>
<script>
export default {
 mounted() {
  this.$nextTick(() => {
   this.$bus.$emit("test", "go");
  });
 },
};
</script>

这里的儿子2组件只能使用 $on 来触发Grandson1组件事件

<template>
 <div>儿子2</div>
</template>
<script>
export default {
 mounted() {
  this.$bus.$on("test", (data) => {
   console.log(data);
  });
 },
};
</script>

8、Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

八种Vue组件间通讯方式合集(推荐) 

具体文档查阅

 结尾

到此这篇关于八种Vue组件间通讯方式合集(推荐)的文章就介绍到这了,更多相关八种Vue组件间通讯方式合集(推荐)内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
网页自动跳转代码收集
Sep 27 Javascript
JavaScript 垃圾回收机制分析
Oct 10 Javascript
javascript中setTimeout的问题解决方法
May 08 Javascript
Javascript Objects详解
Sep 04 Javascript
js模拟淘宝网的多级选择菜单实现方法
Aug 18 Javascript
js实现黑色简易的滑动门网页tab选项卡效果
Aug 31 Javascript
jQuery 调用WebService 实例讲解
Jun 28 Javascript
React根据宽度自适应高度的示例代码
Oct 11 Javascript
利用HBuilder打包前端开发webapp为apk的方法
Nov 13 Javascript
详解javascript中的变量提升和函数提升
May 24 Javascript
微信小程序中如何计算距离某个节日还有多少天
Jul 15 Javascript
利用JS判断元素是否为数组的方法示例
Jan 08 Javascript
小程序实现上传视频功能
Aug 18 #Javascript
如何在selenium中使用js实现定位
Aug 18 #Javascript
vue实现移动端input上传视频、音频
Aug 18 #Javascript
React冒泡和阻止冒泡的应用详解
Aug 18 #Javascript
JavaScript数组排序的六种常见算法总结
Aug 18 #Javascript
js实现简单扫雷
Nov 27 #Javascript
基于JavaScript实现大文件上传后端代码实例
Aug 18 #Javascript
You might like
php使用标签替换的方式生成静态页面
2015/05/21 PHP
php获取远程文件的内容和大小
2015/11/03 PHP
PHP实现二叉树深度优先遍历(前序、中序、后序)和广度优先遍历(层次)实例详解
2018/04/20 PHP
php与阿里云短信接口接入操作案例分析
2020/05/27 PHP
javascript 的Document属性和方法集合
2010/01/25 Javascript
js自动查找select下拉的菜单并选择(示例代码)
2014/02/26 Javascript
Jquery Ajax方法传值到action的方法
2014/05/11 Javascript
jscript读写二进制文件的方法
2015/04/22 Javascript
BootStrap智能表单实战系列(八)表单配置json详解
2016/06/13 Javascript
js 弹出虚拟键盘修改密码的简单实例
2016/10/10 Javascript
setTimeout学习小结
2017/02/08 Javascript
easyui简介_动力节点Java学院整理
2017/07/14 Javascript
动态创建Angular组件实现popup弹窗功能
2017/09/15 Javascript
vue路由跳转时判断用户是否登录功能的实现
2017/10/26 Javascript
基于Vue el-autocomplete 实现类似百度搜索框功能
2019/10/25 Javascript
如何基于原生javaScript生成带图片的二维码
2019/11/21 Javascript
[51:22]Fnatic vs IG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python中splitlines()方法的使用简介
2015/05/20 Python
python xml.etree.ElementTree遍历xml所有节点实例详解
2016/12/04 Python
基于python socketserver框架全面解析
2017/09/21 Python
Python Socket使用实例
2017/12/18 Python
Python函数any()和all()的用法及区别介绍
2018/09/14 Python
pycharm打开命令行或Terminal的方法
2019/01/16 Python
python实现文件批量编码转换及注意事项
2019/10/14 Python
python3 实现调用串口功能
2019/12/26 Python
在tensorflow中设置保存checkpoint的最大数量实例
2020/01/21 Python
python实现人脸签到系统
2020/04/13 Python
PyTorch的torch.cat用法
2020/06/28 Python
django中cookiecutter的使用教程
2020/12/03 Python
解决pycharm修改代码后第一次运行不生效的问题
2021/02/06 Python
HTTP状态码详解
2021/03/18 杂记
计算机应用专业应届毕业生中文求职信范文
2013/11/29 职场文书
大学生村官承诺书
2014/03/28 职场文书
农村党支部书记司法四风问题对照检查材料
2014/09/26 职场文书
员工工作能力评语
2014/12/31 职场文书
网吧员工管理制度
2015/08/05 职场文书