八种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 相关文章推荐
共享自己写一个框架DreamScript
Jan 20 Javascript
checkbox全选/取消全选以及checkbox遍历jQuery实现代码
Dec 02 Javascript
Jquery Ajax学习实例6 向WebService发出请求,返回DataSet(XML) 异步调用
Mar 18 Javascript
js调用浏览器打印模块实现点击按钮触发自定义函数
Mar 21 Javascript
javascript搜索框效果实现方法
May 14 Javascript
关于网页中的无缝滚动的js代码
Jun 09 Javascript
完美实现js焦点轮播效果(二)(图片可滚动)
Mar 07 Javascript
js实现京东轮播图效果
Jun 30 Javascript
vue  自定义组件实现通讯录功能
Sep 30 Javascript
vue实现的树形结构加多选框示例
Feb 02 Javascript
微信小程序实现批量倒计时功能
Nov 01 Javascript
关于IDEA中的.VUE文件报错 Export declarations are not supported by current JavaScript version
Oct 17 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
给ECShop添加最新评论
2015/01/07 PHP
8个必备的PHP功能开发
2015/10/02 PHP
PHP面向对象程序设计组合模式与装饰模式详解
2016/12/02 PHP
PHP全功能无变形图片裁剪操作类与用法示例
2017/01/10 PHP
PHP添加文字水印或图片水印的水印类完整源代码与使用示例
2019/03/18 PHP
Jsonp 跨域的原理以及Jquery的解决方案
2010/05/18 Javascript
11款新鲜的jQuery插件[附所有demo下载]
2011/01/24 Javascript
JS定时器实例
2013/04/17 Javascript
js replace替换所有匹配的字符串
2014/02/13 Javascript
javascript框架设计读书笔记之数组的扩展与修复
2014/12/02 Javascript
JavaScript设计模式之装饰者模式介绍
2014/12/28 Javascript
js获取鼠标位置实例详解
2015/12/09 Javascript
详解Bootstrap四种图片样式
2016/01/04 Javascript
如何将HTML字符转换为DOM节点并动态添加到文档中详解
2018/08/19 Javascript
JS实现从对象获取对象中单个键值的方法示例
2019/06/05 Javascript
react MPA 多页配置详解
2019/10/18 Javascript
vue2.0 获取从http接口中获取数据,组件开发,路由配置方式
2019/11/04 Javascript
vue+render+jsx实现可编辑动态多级表头table的实例代码
2020/04/01 Javascript
JS实现多功能计算器
2020/10/28 Javascript
[03:58]兄弟们,回来开黑了!DOTA2昔日战友招募宣传视频
2016/07/17 DOTA
python3.3教程之模拟百度登陆代码分享
2014/01/16 Python
Python实现类似jQuery使用中的链式调用的示例
2016/06/16 Python
python爬虫之BeautifulSoup 使用select方法详解
2017/10/23 Python
对Python2与Python3中__bool__方法的差异详解
2018/11/01 Python
python 基于dlib库的人脸检测的实现
2019/11/08 Python
python GUI库图形界面开发之PyQt5日期时间控件QDateTimeEdit详细使用方法与实例
2020/02/27 Python
MxNet预训练模型到Pytorch模型的转换方式
2020/05/25 Python
ziaja齐叶雅官方海外旗舰店:来自波兰的天然护肤品牌
2017/01/02 全球购物
师范大学毕业自我鉴定
2013/11/21 职场文书
食品采购员岗位职责
2014/04/14 职场文书
安全资料员岗位职责范本
2014/06/28 职场文书
2014基层党员批评与自我批评范文
2014/09/24 职场文书
借款民事起诉状范文
2015/05/19 职场文书
用Python创建简易网站图文教程
2021/06/11 Python
《月歌。》宣布制作10周年纪念剧场版《RABBITS KINGDOM THE MOVIE》
2022/04/02 日漫
浅谈css清除浮动(clearfix和clear)的用法
2023/05/21 HTML / CSS