文章目录

  • 一、$children / $parent
  • 二、props / $emit
  • 三、eventBus
  • 四、ref
  • 五、provide / reject
  • 六、$attrs / $listeners
  • 七、localStorage / sessionStorage
  • 八、Vuex

实例以element ui为例。例子从上往下逐渐变复杂(后面例子没有删前面的无用代码,有时间重新整理一下!)

一、$children / $parent

  • 拿到 $children / $parent 即可访问子 / 父 组件的所有变量和方法。
  • 官方说 $children / $parent 仅作为应急的通信方法,其中一个原因就是 $children / $parent仅代表的是根组件下的第一个子/父vue组件(普通html标签不含有vue实例,不包含在内),当位置变化或者之间需要增加新的组件,对应的指向就变了,如以下例子。
  • 一般用在组件简单且不易改变的情形,单独把子组件放在根组件的下一级。
  • 使用实例(复制粘贴即可跑起来看效果):
// 子组件
// 1.创建子组件
<template><div><!-- 注意:template中没有this,这里没有this,即不用this.parentMsg -->我是子组件,父组件的数据:{{parentMsg}}</div>
</template><script>
export default {data() {return {msg: "children",parentMsg:""};},mounted(){console.log(this.$parent)this.parentMsg = this.$parent.msg}
};
</script><style scoped>
</style>
// 父组件
<template><!-- 4.使用 --><div><div class="main">我是父组件,子组件的数据:{{childrenMsg}}</div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><p-com></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: ""};},mounted() {console.log(this.$children)this.childrenMsg = this.$children[0].msg;}
};
</script><style scoped>
</style>

两个vue文件放在同一目录下即可运行。
中间需要间插入el组件时,父子关系变为子孙,获取数据失败:

// 父组件模板改为此
<template><!-- 4.使用 --><div><div class="main">我是父组件,子组件的数据:{{childrenMsg}}</div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><el-card><p-com></p-com></el-card></div>
</template>

然而插入非element组件(即html标签),则父子关系不变:

// 父组件模板改为此
<template><!-- 4.使用 --><div><div class="main">我是父组件,子组件的数据:{{childrenMsg}}</div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><div><p-com></p-com></div></div>
</template>

二、props / $emit

官方推荐的父子关系通信方式,不用在乎层级关系,而且没有多余数据传输,父组件给什么,子组件就拿什么、用什么。(原理也是监听和广播,后第三种方式一样,只不过这是局部的,别忘了@是v-on的省略)。props应该也可以放函数地址然后子组件调用,如果可以的话也可以替代emit(待测)。
父组件:

<template><!-- 4.使用 --><div>父组件:<div class="main">我是父组件,我自己拿的子组件数据:{{childrenMsg}}<el-button type="text" @click="alertBox(true)">点我出弹框</el-button><br />子组件主动给我更新的数据:{{childrenMsg2}}</div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><br />子组件:<p-com:parentMsg2="msg"memo="这是爸爸传给你的字符串"@alertBox="flag=>{alertBox(flag)}"@setParentMsg="msg=>{setMsg(msg)}"></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: "",childrenMsg2: ""};},methods: {alertBox(flag) {alert(`调用了${flag ? "自己" : "爸爸"}的弹框`);},setMsg(msg) {this.childrenMsg2 = msg;}},mounted() {console.log(this.$children);this.childrenMsg = this.$children[1].msg;}
};
</script><style scoped>
</style>

子组件:

<template><div><!-- 注意:template中没有this,这里没有this,即不用this.parentMsg -->我是子组件,我自己拿的父组件数据:{{parentMsg}}<br />爸爸用props传给我的信息:{{parentMsg2}}(备注:{{memo}})<el-button type="text" @click="useParentMethods">点我出弹框,并且修改爸爸的数据</el-button></div>
</template><script>
export default {props: ["parentMsg2", "memo"],data() {return {msg: "children",parentMsg: ""};},methods: {useParentMethods() {this.$emit("alertBox", false);this.$emit("setParentMsg", `看你还嚣张! ${Date().split(' ')[4]}`);}},mounted() {console.log(this.$parent);this.parentMsg = this.$parent.msg;}
};
</script><style scoped>
</style>

三、eventBus

监听和广播:
优点:使用简单,导入即用。
缺点:阅读性差,因为你只能打印出这个bus(vue实例),看到所有的监听事件,但并不知道事件谁用了,在哪用的,用来干什么,所以仅适合小规模开发,非父子组件交互较少场景,仅用来处理非父子组件间的通信。
使用:
1.封装一个bus
model下新建eventBus.js(一般是这个目录)

内容

import Vue from 'vue'var EmitData =  new Vue();
export default EmitData; // 暴露一个vue实例,统一监听、广播所有事件

2.父组件导入并且监听(非父子组件也如此)

<template><!-- 4.使用 --><div>父组件:<div class="main">我是父组件,我自己拿的子组件数据:{{childrenMsg}}<el-button type="text" @click="alertBox(true)">点我出弹框</el-button><br />子组件主动给我更新的数据:{{childrenMsg2}}<div>广播更新时间:{{time}}</div></div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><br />子组件:<p-com:parentMsg2="msg"memo="这是爸爸传给你的字符串"@alertBox="flag=>{alertBox(flag)}"@setParentMsg="msg=>{setMsg(msg)}"></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";
import eventBus from "@/model/eventBus.js";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: "",childrenMsg2: "",time: ""};},methods: {alertBox(flag) {alert(`调用了${flag ? "自己" : "爸爸"}的弹框`);},setMsg(msg) {this.childrenMsg2 = msg;}},mounted() {console.log(this.$children);this.childrenMsg = this.$children[1].msg;eventBus.$on("updateTime", time => {this.time = time;});}
};
</script><style scoped>
</style>

3.子组件导入并且广播(触发事件)(非父子组件也如此)

<template><div><!-- 注意:template中没有this,这里没有this,即不用this.parentMsg -->我是子组件,我自己拿的父组件数据:{{parentMsg}}<br />爸爸用props传给我的信息:{{parentMsg2}}(备注:{{memo}})<el-button type="text" @click="useParentMethods">点我出弹框,并且修改爸爸的数据</el-button><el-button @click="updateParentTime">点我更新时间</el-button></div>
</template><script>
import eventBus from "@/model/eventBus.js";export default {props: ["parentMsg2", "memo"],data() {return {msg: "children",parentMsg: ""};},methods: {useParentMethods() {this.$emit("alertBox", false);this.$emit("setParentMsg", `看你还嚣张! ${Date().split(' ')[4]}`);},updateParentTime(){eventBus.$emit("updateTime",Date().split(' ')[4])}},mounted() {console.log(this.$parent);this.parentMsg = this.$parent.msg;}
};
</script><style scoped>
</style>

移除监听:

eventBus.$off('updateTime', {})

四、ref

如果在普通的 DOM 元素上使用ref,引用指向的就是 DOM 元素;如果用在element组件上,引用就指向组件vue实例,可以通过实例直接调用组件的方法、数据或 DOM 元素。
所以ref是单向的,父操作子的数据和方法。
使用:
给子组件注入ref=“xx”,之后xx就是这个子组件的实例了(在this.$refs.xx调用时要注意他是最后加载的,一般为了确保加载完成可以使用setTimeout或者this.$nextTick(()=>{this.$refs.xx}))
子组件不用变,父组件增加ref

<template><!-- 4.使用 --><div>父组件:<div class="main">我是父组件,我自己拿的子组件数据:{{childrenMsg}}<el-button type="text" @click="alertBox(true)">点我出弹框</el-button><br />子组件主动给我更新的数据:{{childrenMsg2}}<div>广播更新时间:{{time}}</div><el-button @click="getChild()">点我使用refs拿子组件数据和方法</el-button></div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><br />子组件:<p-com:parentMsg2="msg"memo="这是爸爸传给你的字符串"@alertBox="flag=>{alertBox(flag)}"@setParentMsg="msg=>{setMsg(msg)}"ref="pCom"></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";
import eventBus from "@/model/eventBus.js";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: "",childrenMsg2: "",time: ""};},methods: {alertBox(flag) {alert(`调用了${flag ? "自己" : "爸爸"}的弹框`);},setMsg(msg) {this.childrenMsg2 = msg;},getChild(){alert("子组件msg:"+this.$refs.pCom.msg+" ;并且更新自己的时间")this.$refs.pCom.updateParentTime()}},mounted() {console.log(this.$children);this.childrenMsg = this.$children[1].msg;eventBus.$on("updateTime", time => {this.time = time;});}
};
</script><style scoped>
</style>

五、provide / reject

provide/ inject 是vue2.2.0新增的api,在组件多层嵌套的时候,根组件只要通过provide来提供变量, 然后任意子组件(孙组件、重孙等等)中通过inject来注入变量(注入this中)即可拿到根组件数据、方法。不局限于只能从当前父组件的props属性中获取数据、方法。由此可知,provide / reject是单向的,只提供子孙等组件获取根组件数据、方法。
父组件:

<template><!-- 4.使用 --><div>父组件:<div class="main">我是父组件,我自己拿的子组件数据:{{childrenMsg}}<el-button type="text" @click="alertBox(true)">点我出弹框</el-button><br />子组件主动给我更新的数据:{{childrenMsg2}}<div>广播更新时间:{{time}}</div><el-button @click="getChild()">点我使用refs拿子组件数据和方法</el-button></div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><br />子组件:<p-com:parentMsg2="msg"memo="这是爸爸传给你的字符串"@alertBox="flag=>{alertBox(flag)}"@setParentMsg="msg=>{setMsg(msg)}"ref="pCom"></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";
import eventBus from "@/model/eventBus.js";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: "",childrenMsg2: "",time: ""};},provide() {return {rootMsg: this.msg,rootAlertBox: this.alertBox};},methods: {alertBox(flag) {alert(`调用了${flag ? "自己" : "爸爸"}的弹框`);},setMsg(msg) {this.childrenMsg2 = msg;},getChild() {alert("子组件msg:" + this.$refs.pCom.msg + " ;并且更新自己的时间");this.$refs.pCom.updateParentTime();}},mounted() {console.log(this.$children);this.childrenMsg = this.$children[1].msg;eventBus.$on("updateTime", time => {this.time = time;});}
};
</script><style scoped>
</style>

子组件:

<template><div><!-- 注意:template中没有this,这里没有this,即不用this.parentMsg -->我是子组件,我自己拿的父组件数据:{{parentMsg}}<br />爸爸用props传给我的信息:{{parentMsg2}}(备注:{{memo}})<el-button type="text" @click="useParentMethods">点我出弹框,并且修改爸爸的数据</el-button><el-button @click="updateParentTime">点我更新时间</el-button><el-button @click="userPJ()">点我看看provide / reject有没有获取到</el-button></div>
</template><script>
import eventBus from "@/model/eventBus.js";export default {props: ["parentMsg2", "memo"],data() {return {msg: "children",parentMsg: ""};},inject: {rootMsg: { default: "获取根组件数据失败" },rootAlertBox: {default: () => {return "获取根组件函数失败";}}},methods: {useParentMethods() {this.$emit("alertBox", false);this.$emit("setParentMsg", `看你还嚣张! ${Date().split(" ")[4]}`);},updateParentTime() {eventBus.$emit("updateTime", Date().split(" ")[4]);},userPJ(){alert(this.rootMsg)this.rootAlertBox()}},mounted() {console.log(this.$parent);this.parentMsg = this.$parent.msg;}
};
</script><style scoped>
</style>

六、$attrs / $listeners

在vue2.4中,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。

inheritAttrs:默认值true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继承特性设置inheritAttrs: false,但是class属性会继承(简单的说,inheritAttrs:true 继承除props之外的所有属性;inheritAttrs:false 只继承class属性)

$attrs–继承所有的父组件属性(除了prop传递的属性、class 和 style ),一般用在子组件的子元素上,如第一个例子的

$listeners–属性,它是一个对象,里面包含了作用在这个组件上的所有监听器,你就可以配合 v-on="$listeners" 将所有的事件监听器指向这个组件的某个特定的子元素。(相当于子组件继承父组件的事件)
实现:

1.同级创建pCom的子组件ppCom

<template><el-button @click="runGrand()">点我调用 attrs / listeners</el-button>
</template>
<script>
export default {methods: {runGrand() {alert(this.$attrs.noProp);this.$listeners.alertBox(false);}},mounted() {console.log(this.$attrs);console.log(this.$listeners);}
};
</script>

2.pCom

<template><div><!-- 注意:template中没有this,这里没有this,即不用this.parentMsg -->我是子组件,我自己拿的父组件数据:{{parentMsg}}<br />爸爸用props传给我的信息:{{parentMsg2}}(备注:{{memo}})<el-button type="text" @click="useParentMethods">点我出弹框,并且修改爸爸的数据</el-button><el-button @click="updateParentTime">点我更新时间</el-button><el-button @click="userPJ()">点我看看provide / reject有没有获取到</el-button><!-- attrs:在模板外需要用this.$attrs获取,他包含了父组件的所有数据listeners:在模板外需要用this.$listeners获取,他包含了父组件的所有事件(监听)inheritAttrs - 默认true:inheritAttrs:true 子标签继承除props之外的所有特性;inheritAttrs:false 只继承class属性传给下一级,注入到他的this上--><br />pCom的子组件:<my-ppcom v-bind="$attrs" v-on="$listeners" ></my-ppcom></div>
</template><script>
import eventBus from "@/model/eventBus.js";
import ppCom from "./ppCom"export default {props: ["parentMsg2", "memo"],components:{"my-ppcom":ppCom},data() {return {msg: "children",parentMsg: ""};},inject: {rootMsg: { default: "获取根组件数据失败" },rootAlertBox: {default: () => {return "获取根组件函数失败";}}},methods: {useParentMethods() {this.$emit("alertBox", false);this.$emit("setParentMsg", `看你还嚣张! ${Date().split(" ")[4]}`);},updateParentTime() {eventBus.$emit("updateTime", Date().split(" ")[4]);},userPJ(){alert(this.rootMsg)this.rootAlertBox()}},mounted() {console.log(this.$parent);this.parentMsg = this.$parent.msg;}
};
</script><style scoped>
</style>

3.父组件

<template><!-- 4.使用 --><div>父组件:<div class="main">我是父组件,我自己拿的子组件数据:{{childrenMsg}}<el-button type="text" @click="alertBox(true)">点我出弹框</el-button><br />子组件主动给我更新的数据:{{childrenMsg2}}<div>广播更新时间:{{time}}</div><el-button @click="getChild()">点我使用refs拿子组件数据和方法</el-button></div><!-- 单独放在根组件的下一级,保证层级关系不被影响 --><br />子组件:<p-com:parentMsg2="msg"memo="这是爸爸传给你的字符串"@alertBox="flag=>{alertBox(flag)}"@setParentMsg="msg=>{setMsg(msg)}"ref="pCom"noProp="子组件不要prop接受我,这是给孙组件的字符串"></p-com></div>
</template><script>
// 2.引入
import pCom from "./pCom";
import eventBus from "@/model/eventBus.js";export default {components: { pCom }, // 3.挂载data() {return {msg: "parent",childrenMsg: "",childrenMsg2: "",time: ""};},provide() {return {rootMsg: this.msg,rootAlertBox: this.alertBox};},methods: {alertBox(flag) {alert(`调用了${flag ? "自己" : "爸爸"}的弹框`);},setMsg(msg) {this.childrenMsg2 = msg;},getChild() {alert("子组件msg:" + this.$refs.pCom.msg + " ;并且更新自己的时间");this.$refs.pCom.updateParentTime();}},mounted() {console.log(this.$children);this.childrenMsg = this.$children[1].msg;eventBus.$on("updateTime", time => {this.time = time;});}
};
</script><style scoped>
</style>

七、localStorage / sessionStorage

通信比较简单,数据和状态比较混乱,不太容易维护。
localStorage 将数据存入浏览器,关闭浏览器再次打开仍然存在,需要手动清除;
sessionStorage将数据存在对话框,关闭这个页面就没了。
他们的操作几乎是一样的,也都是js内置方法,也可以自己封装以下(我的另一篇博客有封装localStorage vue项目将token存在(vuex)store和localstorage中)。使用原生的话注意每次存入要JSON格式化,拿出要JSON解析。

localStorage 使用:

在任何地方使用 localStorage.setItem("k", JSON.stringify("v"))存入数据(方法-函数地址);
在任何地方使用 JSON.parse(localStorage.getItem("k")) 读取数据(方法-函数地址);
任何地方包括vue实例以外,因为他是原生js。

八、Vuex

数据状态管理器,适用于数据复杂、交互频繁场景,选择时要在不使用vue的困难和使用vuex的繁琐中权衡,当然啦,不管用不用都应该拿个例子来学,见我的另一篇博客
Vue使用Vuex一步步封装并使用store

Vue.js中的8种组件间的通信方式;3个组件实例是前6种通信的实例,组件直接复制粘贴即可看到运行结果相关推荐

  1. php动态写入vue,Vue.js中使用动态组件的方法

    本文介绍了如何在Vue.js中引用组件中的HTML元素.您可以通过使用Vue路由器或创建动态组件来切换视图或组件模板. Vue路由器用于在DOM中的视图或组件模板之间导航.要使用Vue路由器,请在ro ...

  2. html5怎么改为vue_是否还在疑惑Vue.js中组件的data为什么是函数类型而不是对象类型...

    点击上方"前端印象",选择"设为星标"第一时间关注技术干货! 引言 要理解本篇文章,必须具备JavaScript中基本数据类型和引用数据类型的概念,大家可以花两 ...

  3. vue.js中<Transition> 组件

    在vue.js中发现 这个过渡动画的组件 简单的可以使用 如果需要复杂的动画效果可以自己引入动画库

  4. vue.js中DES、RSA、SHA1、MD5这四种加密算法的使用

    vue.js中DES.RSA.SHA1.MD5这四种加密算法的使用 DES RSA SHA1 MD5 DES 美国 数据加密标准(DES)是对称密码算法,就是加密密钥能够从解密密钥中推算出来,反过来也 ...

  5. ie浏览器查看vue中js_浅析 Vue.js 中那些空间换时间的操作

    Hello,各位小伙伴,接下来的一段时间里,我会把我的课程<Vue.js 3.0 核心源码解析>中问题的答案陆续在我的公众号发布,由于课程的问题大多数都是开放性的问题,所以我的答案也不一定 ...

  6. 组件间的通信方式(三种)

    1.props 首先适用于父传子 父组件向子组件传递数据时,要在父组件中引入子组件,在子组件引入的地方绑定一个属性,属性值 就是父组件向子组件传递的数据 这个自定义属性的属性值就是存放父组件向子组件传 ...

  7. Vue.js 中的渲染函数是什么?如何使用渲染函数?

    Vue.js 中的渲染函数是什么?如何使用渲染函数? Vue.js 是一款流行的前端框架,它提供了许多方便的工具和 API,用于构建交互式的用户界面.其中,渲染函数是 Vue.js 中一个强大的工具, ...

  8. 浅析Vue.js 中的条件渲染指令

    1 应用于单个元素 Vue.js 中的条件渲染指令可以根据表达式的值,来决定在 DOM 中是渲染还是销毁元素或组件. html: <div id="app"> < ...

  9. Vue.js中的v-model指令(双向绑定)

    Vue.js中v-model的作用 v-model的作用和使用场景 1.v-model的作用--双向绑定 2.v-model双向绑定的使用场景--表单 3.总结 v-model的作用和使用场景 你好! ...

最新文章

  1. 人人都能看懂的LSTM
  2. js 判断多个关键词_2020关键词优化,做好这三点效果立现!
  3. Interview:算法岗位面试—10.25早上—上海某电公司算法岗位(偏图像算法,国企)技术面试之比赛历程、项目收获(Pytorch和Tensorflow)、未来方向
  4. 正则表达式_月隐学python第20课
  5. 垃圾回收算法以及垃圾回收器_什么是垃圾回收?
  6. 根据运算符优先级解析SQL规则表达式
  7. 作为餐饮店长最需要什么能力?
  8. 公众号小tips(持续更新)
  9. POJ 1915 经典马步 双向bfs
  10. python怎么爬取知乎回答并制作词云_使用python爬取流浪地球影评并制作词云,看看别人都说了些说什么...
  11. php闭包 js闭包,JavaScript闭包与PHP闭包的区别是什么?
  12. 矩张量计算 matlab,用来计算广义相对论常用张量计算的Matlab程序
  13. 计算机里的音乐怎么设置,realtek高清晰音频管理器怎么设置
  14. linux 声卡驱动测试,Linux声卡驱动移植和测试
  15. win7 下修改无限网卡Mac地址
  16. [Adaptive Autosar]深入理解--学习资料汇总
  17. openGL基础光照“ADS”( Phone光照模型)(一)
  18. leetcode 寻找峰值
  19. 如何批量调整Word中mathtype公式的大小
  20. 06.设计模式之观察者模式

热门文章

  1. 成立出版社的条件_创始人亲述:法国鸿飞文化出版社的诞生故事和做书心得
  2. 线程条件控制实现线程的同步
  3. 微信接口请求次数_接口签名验证常用方案
  4. 19岁中专学历是怎么在广州找到前端工作的?
  5. webRTC——浏览器里的音视频通话 1
  6. webpack 配置详解
  7. Linux系统开机自启流程
  8. yii 前后台分离及登陆验证
  9. http://blog.csdn.net/myan/article/details/1906
  10. Samba服务器简介及自动挂载配置案例