我们首先定义了两个msg,一个给子组件展示,另一个给孙组件展示,首先将这两个数据传递到子组件中,同时将两个改变msg的函数传入。
在子组件中我们通过props获取子组件所需要的参数,即childMsg;剩余的参数就被归到了$attrs
对象中,我们可以在页面中展示出来,然后把它继续往孙组件中传;同时把所有的监听函数归到$listeners,也继续往下传。
在孙组件中我们继续取出所需要的数据进行展示或者操作,运行结果如下:
当我们在组件上赋予一个非prop声明时,比如child组件上的notuse和grandchildmsg属性我们没有用到,编译之后的代码会把这个属性当成原始属性对待,添加到html原生标签上,所以我们查看代码是这样的:
这样会很难看,我们可以在组件上加上inheritAttrs
属性将它去掉:
总结: a t t r s 和 attrs和 attrs和listeners很好的解决了跨一级组件传值的问题。
provide和inject
虽然 a t t r s 和 attrs和 attrs和listeners可以很方便的从父组件传值到孙组件,但是如果跨了三四级,并且想要的数据已经被上级组件取出来,这时$attrs就不能解决了。
provide/inject是vue2.2+
版本新增的属性,简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。这里inject注入的变量不像$attrs
,只能向下一层;inject不论子组件嵌套有多深,都能获取到。
我们在父组件通过provide注入了两个变量,并且在两秒之后修改变量的值,然后就在子组件和孙组件取出来。
运行结果如下:
可以看到子组件和孙组件都能取出值,并且渲染出来。需要注意的是,一旦子组件注入了某个数据,在data中就不能再声明这个数据了。
同时,过了两秒后我们发现childmsg和grandmsg的值并没有按照预期的改变,也就是说子组件并没有响应修改后的值,官网的介绍是这么说的:
提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
vue并没有把provide和inject设计成响应式的,这是vue故意的,但是如果传入了一个可监听的对象,那么就可以响应了:
那么为什么上面的props和$attrs都是响应式的,连破坏“单向数据流”的.sync
修饰符都是响应式的,但到了provide/inject就不是响应式的了呢?在网上找了半天的资料也没有找到确切的答案,本文就此结束。
END
就这么结束了吗?当然没有!在一(zi)个(ji)哥(xue)们(xi)的帮(yuan)助(ma)下,我总算找到了答案。首先我们试想一下,如果有多个子组件同时依赖于一个父组件提供的数据,那么一旦父组件修改了该值,那么所有组件都会受到影响,这是我们不希望看到的;这一方面增加了耦合度,另一方面使得数据变化不可控制。接着看一下vue是怎么来实现provide/inject的。
可以看到初始化provide的时候将父组件的provide挂载到_provided
,但它不是一个响应式的对象;然后子组件通过$parent
向上查找所有父组件的_provided
获取第一个有目标属性的值,然后遍历绑定到子组件上;因为只是初始化的时候绑定的,而且_provided
也不是响应式的,所以造成了provide/inject的这种特性。
那么provide/inject这么危险,又不是响应式的,它能拿来做什么呢?打开element-ui
的源码搜索provide,我们可以看到非常多的组件使用了provide/inject,我们就拿form、form-item和button举个例子。
form和form-item都可以传入一个属性size来控制子组件的尺寸,但是子组件的位置是不固定的,可能会嵌套了好几层el-row或者el-col,如果一层一层的通过props传size下去会很繁琐,这是provide/inject就派上用处了。
我们通过父组件将elFormItem本身注入到子组件中,子组件通过inject获取父组件本身然后动态地计算buttonSize。
总结:provide/inject能够解决多层组件嵌套传值的问题,但是是非响应的,即provide与inject之间没有绑定,注入的值是在子组件初始化过程中决定的。
EventBus
EventBus
我刚开始直接翻译理解为事件车
,但比较官方的翻译是事件总线
。它的实质就是创建一个vue实例,通过一个空的vue实例作为桥梁实现vue组件间的通信。它是实现非父子组件通信的一种解决方案,所有的组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的“灾难”。
首先创造一个空的vue对象并将其导出,他是一个不具备DOM
的组件,它具有的仅仅只是它实例方法而已,因此它非常的轻便。
将其挂载到全局,变成全局的事件总线,这样在组件中就能很方便的调用了。
我们先定义了两个子组件child1和child2,我们希望这两个组件能够直接给对方发送消息。
我们初始化时在child1和child2中分别注册了两个接收事件,然后点击按钮时分别触发这两个自定义的事件,并传入数据,最后两个组件分别能接收到对方发送的消息,最后效果如下:
前面也提到过,如果使用不善,EventBus会是一种灾难,到底是什么样的“灾难”了?大家都知道vue是单页应用,如果你在某一个页面刷新了之后,与之相关的EventBus会被移除,这样就导致业务走不下去。还要就是如果业务有反复操作的页面,EventBus在监听的时候就会触发很多次,也是一个非常大的隐患。这时候我们就需要好好处理EventBus在项目中的关系。通常会用到,在页面或组件销毁时,同时移除EventBus事件监听。
总结:EventBus可以用来很方便的实现兄弟组件和跨级组件的通信,但是使用不当时也会带来很多问题;所以适合逻辑并不复杂的小页面,逻辑复杂时还是建议使用vuex。
vuex
在vue组件开发中,经常会遇到需要将当前组件的状态传递给其他非父子组件组件,或者一个状态需要共享给多个组件,这时采用上面的方式就会非常麻烦。vue提供了另一个库vuex来解决数据传递的问题;刚开始上手会感觉vuex非常的麻烦,很多概念也容易混淆,不过不用担心,本文不深入讲解vuex。
vuex实现了单向的数据流,在全局定义了一个State对象用来存储数据,当组件要修改State中的数据时,必须通过Mutation进行操作。
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
总结
阿里十分注重你对源码的理解,对你所学,所用东西的理解,对项目的理解。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
vert/ef336fc6eeb8c79b1e96f97e168df90a.png)
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】