八种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与函数式编程解释
Apr 27 Javascript
jQuery Flash/MP3/Video多媒体插件
Jan 18 Javascript
使用jquery获取网页中图片高度的两种方法
Sep 26 Javascript
一个很有趣3D球状标签云兼容IE8
Aug 22 Javascript
javascript中call,apply,bind的用法对比分析
Feb 12 Javascript
javascript中replace( )方法的使用
Apr 24 Javascript
解决jquery实现的radio重新选中的问题
Jul 03 Javascript
js定时器实例分享
Dec 20 Javascript
通过button将form表单的数据提交到action层的实例
Sep 08 Javascript
利用three.js画一个3D立体的正方体示例代码
Nov 19 Javascript
深入分析jQuery.one() 函数
Jun 03 jQuery
通过高德地图API获得某条道路上的所有坐标用于描绘道路的方法
Aug 24 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 分页函数multi() discuz
2009/06/21 PHP
php的大小写敏感问题整理
2011/12/29 PHP
在PHP中使用redis
2013/11/04 PHP
写一段简单的PHP建立文件夹代码
2015/01/06 PHP
thinkphp3.x连接mysql数据库的方法(具体操作步骤)
2016/05/19 PHP
php rsa 加密,解密,签名,验签详解
2016/12/06 PHP
总结的一些PHP开发中的tips(必看篇)
2017/03/24 PHP
ExtJS扩展 垂直tabLayout实现代码
2009/06/21 Javascript
js 对象是否存在判断
2009/07/15 Javascript
jQuery学习笔记之jQuery动画效果
2013/09/09 Javascript
JavaScript判断textarea值是否为空并给出相应提示
2014/09/04 Javascript
JavaScript字符串对象charAt方法入门实例(用于取得指定位置的字符)
2014/10/17 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
js实现简单的联动菜单效果
2015/08/19 Javascript
Angular2 (RC4) 路由与导航详解
2016/09/21 Javascript
Bootstrap轮播插件使用代码
2016/10/11 Javascript
详解使用 Node.js 开发简单的脚手架工具
2018/06/08 Javascript
微信小程序自定义tab实现多层tab嵌套功能
2018/06/15 Javascript
vue中eslintrc.js配置最详细介绍
2018/12/21 Javascript
Node.js + express基本用法教程
2019/03/14 Javascript
详解vue beforeRouteEnter 异步获取数据给实例问题
2019/08/09 Javascript
使用easyui从servlet传递json数据到前端页面的两种方法
2019/09/05 Javascript
谈谈node.js中的模块系统
2020/09/01 Javascript
Python解析nginx日志文件
2015/05/11 Python
浅析python中的分片与截断序列
2016/08/09 Python
详解django中url路由配置及渲染方式
2019/02/25 Python
opencv导入头文件时报错#include的解决方法
2019/07/31 Python
基于python实现雪花算法过程详解
2019/11/16 Python
python 实现矩阵按对角线打印
2019/11/29 Python
Python读写操作csv和excle文件代码实例
2020/03/16 Python
CSS3实现各种图形的示例代码
2016/10/19 HTML / CSS
J2EE模式面试题
2016/10/11 面试题
教师求职自荐信范文
2015/03/04 职场文书
校长师德表现自我评价
2015/03/05 职场文书
员工年度工作总结2015
2015/05/18 职场文书
85句关于理想的名言警句大全
2019/08/22 职场文书