八种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 相关文章推荐
由Javascript实现的页面日历
Nov 04 Javascript
关于jquery ajax 调用带参数的webservice返回XML数据一个小细节
Jul 31 Javascript
网页整体变灰白色(兼容各浏览器)实例
Apr 21 Javascript
jQuery .attr()和.removeAttr()方法操作元素属性示例
Jul 16 Javascript
DOM基础教程之事件对象
Jan 20 Javascript
js控制页面的全屏展示和退出全屏显示的方法
Mar 10 Javascript
jQuery实现的数值范围range2dslider选取插件特效多款代码分享
Aug 27 Javascript
Node.js的Express框架使用上手指南
Mar 12 Javascript
bootstrap css样式之表单
Jan 19 Javascript
详解基于Bootstrap+angular的一个豆瓣电影app
Jun 26 Javascript
微信小程序实现打开内置地图功能【附源码下载】
Dec 07 Javascript
Vue项目总结之webpack常规打包优化方案
Jun 06 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 str_pad() 将字符串填充成指定长度的字符串
2010/02/23 PHP
PHP批量上传图片的具体实现方法介绍.
2014/02/26 PHP
PHP判断是否有Get参数的方法
2014/05/05 PHP
php实现SAE上使用storage上传与下载文件的方法
2015/06/29 PHP
php 的多进程操作实践案例分析
2020/02/28 PHP
javascript call方法使用说明
2010/01/11 Javascript
js实现的map方法示例代码
2014/01/13 Javascript
JavaScript 事件对象介绍
2015/04/13 Javascript
jQuery遮罩层效果实例分析
2016/01/14 Javascript
详谈js中数组(array)和对象(object)的区别
2017/02/27 Javascript
jQuery表格(Table)基本操作实例分析
2017/03/10 Javascript
基于Node.js的WebSocket通信实现
2017/03/11 Javascript
js 去掉字符串前后空格实现代码集合
2017/03/25 Javascript
angularjs实现table增加tr的方法
2018/02/27 Javascript
vue多层嵌套路由实例分析
2019/03/19 Javascript
bootstrap table插件动态加载表头
2019/07/19 Javascript
vue vant Area组件使用详解
2019/12/09 Javascript
微信小程序点击按钮动态切换input的disabled禁用/启用状态功能
2020/03/07 Javascript
jQuery实现鼠标滑动切换图片
2020/05/27 jQuery
在VUE style中使用data中的变量的方法
2020/06/19 Javascript
[02:43]DOTA2英雄基础教程 圣堂刺客
2013/12/09 DOTA
[05:34]2014DOTA2国际邀请赛中国区预选赛精彩TOPPLAY第二弹
2014/06/25 DOTA
解决uWSGI的编码问题详解
2017/03/24 Python
python中协程实现TCP连接的实例分析
2018/10/14 Python
python遍历小写英文字母的方法
2019/01/02 Python
Python 3.3实现计算两个日期间隔秒数/天数的方法示例
2019/01/07 Python
pycharm的console输入实现换行的方法
2019/01/16 Python
在Python中使用Neo4j的方法
2019/03/14 Python
TensorFlow tf.nn.conv2d实现卷积的方式
2020/01/03 Python
Django 解决distinct无法去除重复数据的问题
2020/05/20 Python
使用Python实现微信拍一拍功能的思路代码
2020/07/09 Python
介绍一下XMLHttpRequest对象
2012/02/12 面试题
仓管员岗位责任制
2014/02/19 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
预备党员介绍人意见
2015/06/01 职场文书
总结一下关于在Java8中使用stream流踩过的一些坑
2021/06/24 Java/Android