【Vue7】非父子组件之间的传值

重点啊!!当初学这个时候,纠结了好一会儿。
先来看看组件关系。


组件关系

可以把一个网页拆分成很多部分,如图所示,可以理解为一个组件,分成三个部分,顶部、左侧、右侧三个区域。也就是将1号组件再拆分成3个2号子组件,左侧区域进一步细化,可拆分成2个3号子组件,右侧进一步细化,可拆成3个3号子组件。

第二层的组件想和第一层的组件通信,也就是2号想和1号通信,
父组件通过props,和子组件传值;子组件通过事件派发和父组件传值。
那要是第三层组件想和第一层组件通信呢?可以直接通过属性传递吗?这是不行的。那能第一层先和第二层,第二层再和第三层通信,这样也算是第一层和第三层传递。
不过这种传值略显复杂,
如果三号中的第一个想和三号中的最后一个传值呢?

像这样

一步步传上去,再一步步传下来?(;´д`)ゞ

有点晕啊,在Vue之中,像这样非父子组件间的传递(1和3这种爷爷孙子之类的,还有3和3这种兄弟之间的,反正就不是父子之间的),我们可以通过Vuex来解决。还有一种是通过发布订阅模式(观察者模式)来解决,在Vue中叫做总线机制。

new一个Vue的实例,挂载在Vue.prototype.bus上,也就是Vue的prototype上挂载一个bus属性,这个属性指向Vue的实例,只要我们之后调用new Vue或者创建组件的时候,每一个组件都会有bus这个属性,因为每个组件或者每一个Vue的实例都是通过Vue这个类来创建的, 而之前在Vue的类上挂载了一个bus属性,而且是挂在了prototype上, 所以每个通过这个类创建的对象,也就是实例上都有bus属性,它都指向同一个Vue实例。

在这里我们希望当子组件被点击的时候,另一个子组件也相应的更改。怎么将子组件1的内容传递给子组件2呢?
this.bus.$emit('change', this.content)
分解来看,this.bus指的是什么?指的就是实例上挂载的bus,这个bus又是Vue实例,所以它上面就有$emit这个方法,所以就能通过这个方法来派发change事件。

有了派发事件,相应的其他组件就要进行监听。
在这里借助生命周期钩子(不记得的看生命周期那章)
这里借助的是mounted,也就是这个组件被挂载的时候,它会执行的一个钩子函数,在这里让组件去监听bus的改变,这个组件一定会有bus属性,在它上面也一定有$on这个方法,它就能监听到bus上派发的事件,也就是 $emit派发的change事件,这里监听到change事件之后,alert一下,每次点击,都会有2次弹窗。

为什么会有两次弹窗?
因为一个child组件内去触发事件时,两个child组件都进行同一个事件的监听,所以两个组件都会去弹窗,所以有两次弹窗。

利用bus

还没有结束,在mounted执行的$on内,this的作用域发生了改变,所以要将this作用域进行保存,也就是var this_ = this;,下面使用的是保存的this_
但是会报出一个警告。
我是警告

因为child里的content是由父组件传递过来的。子组件是不能强行修改这个内容的。
同样自己定义一个副本,然后修改副本数据就行了。


我用的是自己的selfContent

非父子组件传值就解决啦。不论是兄弟组件还是什么其他非父子组件的通信,比较简单的都可以用这种来解决,复杂的用的是vuex


2019/06/14更新

对于评论中出现的“点击之后,只能修改一次”这个,可以看看虚拟Dom,它将新的对象树与旧的对象树进行对比,记录差异,渲染的是差异部分。对于DOM的操作只变更有不同的地方

回到问题上,当子组件1的值传递给子组件2,对子组件2的值进行修改之后。此时两个组件的值应该是一致的。那么在第二次点击的时候,发现内容并没有新的变化,也就是没有差异,dom并不会进行新的操作。看起来也就只能点击一次。不确定的可以加一行代码。

加一行代码

至于为什么会是两次弹窗,在上面已经有解释啦。


2020/03/31更新

provide 和 inject 2.2.0 新增

这两个为了提供更好的跨组件通信方案。props是一层层向下传,vuex会增加学习、使用成本。而这个会使得组件通信更加简单。

举个栗子

点击前

点击change按钮变成
点击后

分析一下这个例子:

  1. 先是全局定义了一个Demo组件,这个Demo组件中有一个message,另外还有一个Demo2组件
  2. 这个Demo组件中定义了一个change方法,用来更改message的内容
  3. 然后定义了一个Demo2组件,这个组件内包含了Demo3组件
  4. 接下来定义了Demo3组件,这个组件中有一个按钮,这个按钮会调用changeMessage方法,这个方法又会调用父组件的方法来改变message
  5. 最后渲染到页面上。
  6. Demo组件用了provide,将自身this,打包成了elDemo属性,提供给子组件进行调用。也就是子组件可以通过elDemo来找到父组件的实例,不需要通过props一层层传递之类的。
  7. 直接子组件Demo2并没有进行任何操作,而Demo3内通过inject,这是一个数组类型,在数组内标识需要引入的父组件实例。也就是elDemo。
  8. 可直接通过this.elDemo来调用父组件实例,父组件上有一个change方法,所以this.elDemo.change()是直接调用了父组件的change方法,并且向内传入组件名称。
  9. 刚开始时这个组件名称是Demo,而点击之后就会变成了Demo3。

官方文档上的例子

官方文档上的例子
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,040评论 0 29
  • 1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现父组件://这里必须要用 -...
    Splendid飞羽阅读 28,258评论 7 14
  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,971评论 4 129
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,494评论 18 139
  • 饮一杯就忘了春夏 又一杯就惊起了牵挂 再一杯就潇潇暮雨空山和泪下…… ​​​
    君诺c阅读 342评论 2 6