八种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 相关文章推荐
使用自定义setTimeout和setInterval使之可以传递参数和对象参数
Apr 24 Javascript
Jquery跨域获得Json时invalid label错误的解决办法
Jan 11 Javascript
jquery.uploadify插件在chrome浏览器频繁崩溃解决方法
Mar 01 Javascript
JavaScript通过字典进行字符串翻译转换的方法
Mar 19 Javascript
angular实现form验证实例代码
Jan 17 Javascript
Node.js 中exports 和 module.exports 的区别
Mar 14 Javascript
webpack+vue中使用别名路径引用静态图片地址
Nov 20 Javascript
web前端vue之vuex单独一文件使用方式实例详解
Jan 11 Javascript
怎么使用javascript深度拷贝一个数组
Jun 06 Javascript
node基于async/await对mysql进行封装
Jun 20 Javascript
vue-cli配置flexible过程详解
Jul 04 Javascript
JS实现TITLE悬停长久显示效果完整示例
Feb 11 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
便携利器 — TECSUN PL-365简评
2021/03/02 无线电
php实现MD5加密16位(不要默认的32位)
2013/08/12 PHP
php一维二维数组键排序方法实例总结
2014/11/13 PHP
php给图片加文字水印
2015/07/31 PHP
php封装db类连接sqlite3数据库的方法实例
2017/12/19 PHP
jQuery解决iframe高度自适应代码
2009/12/20 Javascript
JQuery中getJSON的使用方法
2010/12/13 Javascript
JavaScript基础知识学习笔记
2014/12/02 Javascript
JS完成画圆圈的小球
2017/03/07 Javascript
微信小程序 页面跳转及数据传递详解
2017/03/14 Javascript
JS中showModalDialog关闭子窗口刷新主窗口用法详解
2017/03/25 Javascript
jQuery实现的点击标题文字切换字体效果示例【测试可用】
2018/04/26 jQuery
JavaScript设计模式之工厂模式简单实例教程
2018/07/03 Javascript
深入理解react-router 路由的实现原理
2018/09/26 Javascript
详解微信小程序网络请求接口封装实例
2019/05/02 Javascript
js console.log打印对象时属性缺失的解决方法
2019/05/23 Javascript
Vue实现点击按钮复制文本内容的例子
2019/11/09 Javascript
Nuxt 项目性能优化调研分析
2020/11/07 Javascript
使用Vant完成Dialog弹框案例
2020/11/11 Javascript
[01:27]2014DOTA2展望TI 剑指西雅图IG战队专访
2014/06/30 DOTA
python处理文本文件并生成指定格式的文件
2014/07/31 Python
Python自动化运维_文件内容差异对比分析
2017/12/13 Python
Python退火算法在高次方程的应用
2018/07/26 Python
python实现文本界面网络聊天室
2018/12/12 Python
英国简约舒适女装品牌:Great Plains
2018/07/27 全球购物
后勤人员自我评价怎么写
2013/09/19 职场文书
汽车检测与维修应届毕业生求职信
2013/10/19 职场文书
酒店总经理欢迎词
2014/01/08 职场文书
经管应届生求职信范文
2014/05/18 职场文书
初中化学教学反思
2016/02/22 职场文书
普希金诗歌赏析(6首)
2019/08/22 职场文书
一文搞懂如何实现Go 超时控制
2021/03/30 Python
ThinkPHP5和ThinkPHP6的区别
2021/03/31 PHP
苹果M1芯片安装nginx 并且部署vue项目步骤详解
2021/11/20 Servers
俄罗斯十大城市人口排名,第三首都仅排第六,第二是北方首都
2022/03/20 杂记
JavaScript声明变量和数据类型的转换
2022/04/12 Javascript