一、为什么要封装组件
首先,一个好问题,面试要考的!为什么要封装组件呢?
提高代码的复用性:通过封装,可以将一段代码或一部分功能抽象为一个独立的组件,并在不同的项目或场景中重复使用。这样可以减少代码的重复编写,提高开发效率。
提供逻辑的封装和隐藏:封装组件可以将复杂的逻辑封装在一个组件内部,对外部提供简单的接口。这样可以隐藏内部实现细节,简化对组件的使用和理解。
维护和更新的便利性:当系统需要修改或更新某个功能时,只需要修改组件内部的实现逻辑,而不需要修改调用该组件的其他部分。这样可以提高系统的可维护性,降低修改代码的风险。
提高团队的协作效率:组件的封装可以让开发团队在开发过程中更好地分工合作。团队成员可以根据各自的专长负责开发不同的组件,然后通过接口协议进行集成和测试。
提高用户体验:通过封装可重用的UI组件,可以确保在不同的页面和应用中保持一致的用户界面和交互,提供更好的用户体验和用户界面的一致性。
二、组件封装需要注意的问题/技巧
封装一个小小的组件也需要注意很多问题,稍不注意将会踩坑,且随着业务需求的不断扩充和项目规模日益壮大,有些小问题会慢慢变成灾难性的大问题。
主要有以下几大注意事项:
1.数据的传递问题
- 单向数据流(只能是父组件传给子组件中的props,反过来不行)
- 组件之间如何传值
- 组件之间的方法如何调用
2.组件的功能和接口设计要合理,要满足用户需求,并且易于使用和理解。
3.组件的封装要考虑可重用性和可扩展性,尽量设计出通用的组件,能够在不同的场景下复用,并且能够方便地进行功能扩展和定制。
4.组件的封装要考虑文档和测试,要提供清晰的文档说明组件的功能和使用方法,并且进行充分的测试,确保组件的质量和稳定性。
三、单向数据流
Vue的官方文档如是说:
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。 额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
下面贴上一个小例子:
子组件:
父组件:
summary:
1.子组件和父组件之间要解耦,出现问题时才能更好地去判断位置,同时,在业务需求不断变更的情况下,能够减少修改维护工作。
2.既不能在子组件中更改自己的props值,也不能去通过子组件控制父组件的值的变化,要保证数据的单向传递。
3.子组件自己的方法用自己的状态去控制,父组件同理,所以有需要的时候,可通过增加一个initXXX来作为初始的赋值操作。
四、组件通信
1、组件传值
父子组件之间传值
父传子:通过props,或者this.$children,或者ref;
通过props将数据从父组件传递给子组件,在子组件中通过props来接收和使用这些数据。
子传父:通过this.$emit,或者this.$parent
子组件可以通过$emit方法触发自定义事件,并将数据传递给父组件进行处理,在父组件中通过v-on来监听和响应这些自定义事件。
隔代传值/爷孙组件传值
爷传孙:通过this.$attrs,或者provide;孙传爷:通过this.$listeners,或者inject
爷孙组件之间的通信可以通过provide和inject来实现。provide和inject允许祖先组件(爷组件)向后代组件(孙组件)传递数据或者方法
通过Provide/Inject:通过在父组件中使用provide提供数据,然后在子组件中使用inject来注入并使用这些数据。这样可以实现跨多层级组件的通信。
兄弟组件传值
通过共同的父组件来传递数据:如果两个组件拥有一个共同的父组件,那么可以在父组件中定义一个数据,并使用props将数据传递给这两个子组件。当一个组件更新数据时,会将数据传递给父组件,再由父组件将数据传递给另一个组件,从而实现兄弟组件之间的通信。
Vuex(状态管理):vuex是Vue的状态管理库,用于管理应用程序的所有状态并将它们集中存储在一个单一的地方。将兄弟组件需要共享的数据存储在vuex中,通过dispatch一个action来改变这个状态的值,并通过getter获取这个状态的值,从而实现兄弟组件之间的通信。
使用事件总线:事件总线是一个空的Vue实例,可以被用来实现Vue实例之间的通信。在事件总线中定义一个事件,当兄弟组件需要通信时,一个组件可以通过事件总线发送一个事件,而另一个组件可以通过事件总线监听这个事件并做出响应。
自定义事件:每个Vue实例都维护着一个事件监听器,可以使用on监听事件,使用emit触发事件。一个兄弟组件可以监听一个自定义事件,而另一个组件则可以通过触发该事件并传递需要通信的数据来实现通信。
最后,通过在Vuex中定义的状态和操作,可以让任意组件进行通信。
2、组件方法调用
父子组件之间方法调用
①Props: 父组件可以通过props将方法传递给子组件,在子组件中可以直接调用这些方法。这种方式适合父组件和子组件之间的单向通信。没错,就是将方法也定义为props。就像这样:
②子组件可以通过$emit方法触发一个自定义事件,并将数据作为参数传递给父组件。在父组件中,可以使用v-on指令监听这个自定义事件,并调用相应的方法。一定要记得@绑定事件啊!!!我本人时常会忘记这个重要的事情。
隔代传值/爷孙组件方法调用
在爷组件中使用provide来提供需要共享的数据或方法,然后在孙组件中使用inject来接收这些数据或方法。这样,孙组件就可以调用爷组件提供的方法了。
需要注意的是,使用provide和inject需要谨慎使用,因为它们会破坏了组件之间的封装性,使得组件之间的耦合性增强。因此,建议只在确实需要在爷孙组件之间共享方法时使用。
兄弟组件方法调用
兄弟组件之间的通信可以通过一个共同的父组件或者全局事件总线(Event Bus)来实现方法的调用。
①通过共同的父组件来实现兄弟组件之间的方法调用:
- 如果两个组件是兄弟关系,它们的共同父组件可以扮演中介的角色,将需要共享的方法定义在共同父组件上,然后通过props将方法传递给兄弟组件。
- 兄弟组件可以通过触发事件来通知父组件,父组件再调用相应的方法,从而实现兄弟组件之间的方法调用。
②通过全局事件总线(Event Bus)来实现兄弟组件之间的方法调用:
- 可以在Vue实例上注册一个事件总线,兄弟组件通过该事件总线来进行通信。
- 一个典型的做法是在Vue实例上注册一个事件总线,然后在其中定义需要共享的方法,兄弟组件可以通过该事件总线来调用方法。
需要注意的是,使用全局事件总线需要谨慎使用,因为它可能导致组件之间的通信关系不明显,增加了代码的复杂性。建议在确实需要在兄弟组件之间共享方法时使用。