设计的面试题

Vue中父子组件通信有哪些方式?

概述

通信方式无外乎就那几种:
Prop 常用$emit 组件封装用的较多.sync 语法糖  (较少)$attrs和$listeners(组件封装用的较多)provide和inject(高阶组件/组件库用的较多)其他方式通信

详情

1 Prop

我们用的最多方式,可以通过Prop向子组件传递数据。
用一个形象的比喻来说,父子组件之间的数据传递相当于自上而下的下水管子,只能从上往下流,不能逆流。这也正是Vue的设计理念之单向数据流。而Prop正是管道和管道之间的一个衔接口,这样(水)数据才能向下流.
看代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Prop</title><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script></head>
<!--父组件传给子组件数值,子组件不要对其进行修改,而是需要找个变量将父组件传递的数值给赋值过来然后对变量进行操作
--><body><div id="app"><counter :count='1'></counter><counter :count='2'></counter></div><script>Vue.component('counter', {props: ['count'],data: function() {return {number: this.count}},template: '<div @click="add">{{number}}----{{count}}</div>',methods: {add: function() {this.number++,}},})let vm = new Vue({el: "#app",})</script>
</body></html>

父组件传给子组件数值,子组件不要对其进行修改,而是需要找个变量将父组件传递的数值给赋值过来然后对变量进行操作.

上面的代码我就是将prop里面父组件穿的count赋值给number,对number进行操作,并不改变count的值。

但是代码中的方式只适合prop里面的数值是原始类型,不能是对象类型,如果count是对象类型,需要进行深拷贝进行赋值,不然的话,改变number的数值,count的数值还是会改变的

浏览器的显示结果:

2 $emit

触发当前实例上的事件。附加参数都会传给监听器回调。
参数:

{string} eventName
[...args]

这个方法是用来子组件向父组件传递数值的,和上面的Porp正好相反.
下面代码:

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>$emit</title><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script></head>
<!--父组件传给子组件数值,子组件不要对其进行修改,而是需要找个变量将父组件传递的数值给赋值过来然后对变量进行操作
--><body><div id="app"><counter @inc="addnumber"></counter></div><script>Vue.component('counter', {template: '<div @click="add">点击一下</div>',methods: {add: function() {this.$emit('inc', '温清夜')}},})let vm = new Vue({el: "#app",data: {total: 5},methods: {addnumber: function(step) {alert(step)}}})</script>
</body></html>

上面就是$emit的用法,在页面中我点击 '点我一下’就会触发上面绑定的事件add,在add里面有个监听事件inc,因此inc监听事件就会被触发(其实inc事件在代码中就可以看出来,直接在父组件上 @inc=“addnumber”,但是是无效的,因为你需要知道inc是个怎样的东西,到底在哪里。所以在子组件你绑定点击事件,来告诉浏览器inc是个啥东西)

该事件相当于

vm.$on('inc',function addnumber(step){alert(step)
})
vm.$emit('inc','温清夜')

3 .sync修饰符

这个东西曾经作为双向绑定功能存在,后来Vue2.0移出,然后在Vue2.3版本引入.
它只是作为一个编译时的语法糖存在,它会被扩展为一个自动更新父组件属性的v-on监听器。说白了就是然我们手动进行更新父组件的值,从而使数据改动来源更加明显。官方用语:

在有些情况下,我们可能需要对一个 prop 进行“双向绑定”。不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。

既然作为一个语法糖,肯定是某种写法的简写形式:看代码

<text-documentv-bind:title="doc.title"v-on:update:title="doc.title = $event"
></text-document>

使用.sync语法糖

<text-document v-bind:title.sync="doc.title"></text-document>

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”doc.title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的属性名,类似 v-model。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>.sync</title><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script></head><body><div id="app"><login :name.sync="userName"></login> {{ userName }}</div><script>let Login = Vue.extend({template: `<div class="input-group"><label>姓名:</label><input v-model="text"></div>`,props: ['name'],data() {return {text: ''}},watch: {text(newVal) {this.$emit('update:name', newVal)}}})let vm = new Vue({el: '#app',data: {userName: ''},components: {Login}})</script>
</body></html>

代码中的一行代码:

  this.$emit('update:name', newVal)

官方语法:

我们推荐以 update:myPropName 的模式触发事件取而代之。举个例子,在一个包含 title prop 的假设的组件中,我们可以用以下方法表达对其赋新值的意图:

this.$emit('update:title', newTitle)

myPropName表示要更新的prop值,如果你不用.sync语法糖使用第二种$emit也可以

4 attrs和attrs和attrs和listeners

$attrs官网的解释

包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用

$listeners官网的解释

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

我觉得attrs和attrs和attrs和listeners属性像两个收纳箱,一个负责收纳属性,一个负责收纳事件,都是以对象的形式来保存数据

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>
</head><body><div id="app"><child :foo="foo" :bar="bar" @one.native="triggerOne" @two="triggerTwo"><child></div><script>let Child = Vue.extend({template: '<h2>{{ foo }}</h2>',props: ['foo'],created() {console.log(this.$attrs, this.$listeners)// -> {bar: "parent bar"}// -> {two: fn}// 这里我们访问父组件中的 `triggerTwo` 方法this.$listeners.two()// -> 'two'}})new Vue({el: '#app',data: {foo: 'parent foo',bar: 'parent bar'},components: {Child},methods: {triggerOne() {alert('one')},triggerTwo() {alert('two')}}})</script>
</body></html>

代码中两个属性个两个方式,区别是,属性是一个prop声明,事件是一个.native修饰器.

我们通过attrs和attrs和attrs和listeners进行数据传递,在需要的地方调用和处理还是比较方便的。


当我们在组件上赋予一个非Prop声明时,编译之后的代码会把这些属性都当成原始属性对待,添加到HTML原生标签上,上面的代码编译后

<h2 bar="parent bar">parent foo</h2>

标签里面的bar属性是什么鬼?如果去掉,这正是inheritAttrs属性的用武之地!给组件加上这个属性就行了,一般是配合$attrs使用:

let Child=Vue.extend({
inheritAttrs:false;//默认是true
})

再次编译

<h2>parent foo</h2>

5 provide/inject

这二个是组合,也就是相互配合使用,缺一不可
官方描述

provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。

总结:小的时候,你父亲什么东西都帮你存着,等你长大结婚找媳妇的时候,你要买车买房,他有的尽量都会满足你.

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script><title>Document</title>
</head><body><div id="app"><son></son></div><script>let Son = Vue.extend({template: '<h2> son {{house}}--{{car}} ---{{money}}</h2>',inject: {house: {default: '没房'},car: {default: '没车'},money: {//长大工作了虽然有点钱 // 仅供生活费,需要向父母要 default: '¥4500'}},created() {console.log(this.house, this.car, this.money)// -> '房子', '车子', '¥10000' }})new Vue({el: '#app',provide: {house: '父亲给的房子',car: '父亲给的车子',money: '父亲给的¥10000'},components: {Son}})</script>
</body></html>

代码很容易看懂,这个二个东西,一个在子组件 inject
另一个在父组件provide

6 其他通信方式

EventBus

思路就是声明一个全局Vue实例变量EventBus,把所有的通信数据,事件监听都存储到这个变量上,这样就到达在组件间实现数据共享,有点类似Vuex。但是这种方式只适合极小的项目,复杂的项目还是推荐Vuex。

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script><title>Document</title>
</head><body><div id="app"><child></child></div><script>// 全局变量let EventBus = new Vue()// 子组件let Child = Vue.extend({template: '<h2>child</h2>',created() {console.log(EventBus.message)// -> 'hello'EventBus.$emit('received', 'from child')}})new Vue({el: '#app',components: {Child},created() {// 变量保存EventBus.message = 'hello'// 事件监听EventBus.$on('received', function(val) {console.log('received: ' + val)// -> 'received: from child'})}})</script>
</body></html>


从显示看,是父子之间双向通信的。

Vuex

官方推荐,VueX是一个专门为Vue.js应用程序开发的状态管理模式

$root

当前组件树的根Vue实例,如果当前实例没有父实例,此实例将会是自己。通过访问根组件也能进行数据之间的交互,但极小情况下回直接修改父组件中的数据.

$parent

父实例,如果当前实例有的话,通过访问父实例也能进行数据之间的交互,但极小情况下回直接修改父组件中的数据

broadcast/dispatch

被删了 ,沃日。大家可以模拟模拟,借鉴借鉴!

Vue的父子组件通信(十种)相关推荐

  1. Vue.js 父子组件通信的十种方式;告诉世界前端也能做 AI;你可能不知道的14个JavaScript调试技巧...

    记得点击文章末尾的"阅读原文"查看哟~ 下面先一起看下本周的摘要吧~ 想了解老用户如何参与阿里云双十一1折拼团特惠主机的,可以看第二条推送,文中提供了两种方法~,一起看看本周有哪些 ...

  2. html中的父子通信代码,Vue.js 父子组件通信的十种方式

    面试官:Vue 中父子组件通信有哪些方式? 自己先想一分钟. 无可否认,现在无论大厂还是小厂都已经用上了 Vue.js 框架,简单易上手不说,教程详尽,社区活跃,第三方套件还多.真的是前端开发人员必备 ...

  3. Vue 非父子组件通信方案

    Vue 非父子组件通信方案 概述 在 Vue 中模块间的通信很普遍 如果是单纯的父子组件间传递信息,父组件可以使用 props 将数据向下传递到子组件,而在子组件中可以使用 events (父组件需要 ...

  4. Vue 非父子组件通信 (ref)

    Vue 非父子组件通信 (ref) 流程:1. 先在son子组件中定义一个数据和事件处理程序data( ) { return { flag: false }} , methods: { cry( ) ...

  5. Vue 非父子组件通信

    前面的话 在实际业务中,除了父子通信外,还有很多非父子组件通信的场景,非父子组件一般有两种,兄弟组件和跨多级组件.Vue.js 2.x中,使用一个空的Vue实例作为中央事件总线(bus). 中央事件总 ...

  6. 【Vue】父子组件通信

    [Vue]父子组件通信 前言 父组件向子组件传值 法一: props 法二: $parent 子组件向父组件传值 $emit $emit + .sync $refs v-model 前言

  7. VUE非父子组件通信Bus——公交车踩坑笔记

    抛开父子组件的通讯,对于非父子组件通信,简单的数据交互,使用Bus是非常不错的. 遇到的坑有两个. 1.两个组件的信息交互代码写在哪个生命周期函数中,如果只是点击组件A标签触发函数,然后向界面B传递参 ...

  8. vue:父子组件通信

    页面增加展示文字 1.进入demo-project项目的src\components目录下新建views目录,并新建First.vue文件 2.进入router目录下的index.js并配置路由路径: ...

  9. vue的父子组件通信

    父子组件通信: 1.父组件向子组件传递数据,子组件可以使用 props 接收父组件的数据 2.子组件可以使用this.$emit触发父组件的自定义事件 父组件通过props向子组件传递数据 第一步:需 ...

最新文章

  1. .NET(C#)连接各类数据库-集锦
  2. java基础——java位运算
  3. python生成50个随机数_Python:如何生成12位随机数?
  4. Linux 0.12内核与现代内核在内存管理上的区别
  5. html模板引擎 字符串长度,Web前端模板引擎の字符串模板
  6. 如何将参数传递给批处理文件?
  7. JAVA构造器的实际使用
  8. 线上 4 台机器同一时间全部 OOM,到底发生了什么?
  9. OpenGL 延迟着色法Deferred Shading
  10. 基于TCP的Socket通讯
  11. Spyder打开报错解决办法
  12. Mapnik使用postgres中的栅格数据
  13. 小程序中的多表联合查询
  14. 冷峭的 渗透测试入门DVWA教程001:环境搭建
  15. Linux系列课程之一Linux的介绍
  16. Premiere Pro CS6自学所需的视频编辑基础(二)
  17. 【冷启动】快手《POSO: Personalized Cold Start Modules for Large-scale Recommender Systems》
  18. Google Play 开发者账号关联 如何解决
  19. 手把手教你用 Tauri+Vue 创建小型桌面应用
  20. SecureCRT调整字体大小

热门文章

  1. Unity 优化建议
  2. 好用的手机号码归属地、吉凶及号码估值查询API接口
  3. 快速排序 Java 针对重复元素
  4. Linux系统调优详解(三)——CPU状态查看相关命令
  5. 第五人格七月三日服务器维护要多久,第五人格微信每日一题7月3日答案是什么_今天有四个人来访过_玩游戏网...
  6. csdn 涨粉攻略 代码(二)粉丝数 webmagic 爬虫
  7. 基于微信小程序的驾校报名系统
  8. word默认文字环绕方式是什么_在word2010中,艺术字默认的文字环绕方式
  9. ubuntu设置网卡默认启动_ubuntu配置网卡的办法
  10. java反射扫描包,获取枚举属性