原文:michaelnthiessen.com/6-levels-of…
在编写代码的时候,谁都想“少干活、多办事”。以组件而言,我们希望它能被不止一次地复用。
一些组件仅需基本的复用性。
另一些则需要更复杂的技术以充分利用。
我认为复用性有 6 中不同的层级,这里大体上来看一下:
1. 模版化
不同于将代码随处复制/粘贴的是,借助模版化可以将其包裹在组件内部。
当复用组件 -- 而不是直接拷贝代码时,给我们带来了两个好处:
- 未来的改动变得简单的多,因为只需要在一处进行
- 无需再记住类似代码被拷贝到的哪几个甚至上百个地方了
这简直太基础了,也是谈及复用性时最常被说起的。
更高一个层级的就有意思些了:
2. 配置
对于某些组件,使用起来是需要变化的。
一个 Button
组件会有个基本的样子,或许也要支持带个图标。与其为每个版本都重新创建一整个新组件,不如使用属性切换其类型。
添加这些属性通常不会对组件改动太多,但却带来了组件使用的更多灵活性。
注意:这跟使用属性影响状态或数据是不同的,比如一个 loading
prop 或 disabled
prop.
3. 适配性
配置的最大问题在于缺乏远见。要预见并支持未来的需求,就得向组件中加入很多属性。
但如果让组件变得“可适配”,在不用改变组件的前提下,就能让其支持我们甚至未曾设想到的场景。
实现的方法是用一个 slot,从父组件中传入一块模版置标。
比如,与直接在 Button
组件上使用一个 text
属性不同的是,我们可以使用 default
slot:
<!-- Button.vue --> <template> <button class="btn btn--default" @click="$emit('click')" > <slot /> </button> </template>
这样一来,就不受制于传递一个 string
、number
还是别的什么了。
如果要增加一个 loading
旋转动画,又不想改动 Button
组件,这样做就好了:
<template> <Button> <img v-if="loading" src="spinner.svg" /> 摁我 </Button> </template>
4. 反转
与向子组件中传入一整块模版置标又有所不同的是,我们还能传入一组指令,以决定其 如何 渲染。
打个比方,这就像自己烹饪和叫外卖的对比。当你按照菜谱自己动手时,虽然要费些事,但却尽在掌握 -- 你可以自己掌控“少许味精”是多少,甚至直接扔掉菜谱自己发挥都可以。
在 Vue 中,使用 scoped slot (作用域插槽) 就可以达到目的,为组件增加更多的灵活性了。
(译注 - 官网上的例子):
<!-- 子组件 CurrentUser --> <span> <slot v-bind:user="user"> {{ user.lastName }} <!--默认值--> </slot> </span> <!-- 父组件 --> <current-user> <template v-slot:default="slotProps"> {{ slotProps.user.age < 10 ? slotProps.user.lastName : `Mr. ${slotProps.user.firstName}` }} </template> </current-user>
5. 扩展
使用 Vue 中的 named slots (具名组件) 可以在组件中添加一个或多个扩展点。再结合上述的适配和反转,就具备了最大化组件复用性的必要技术。下一步就是在组件中贯彻这些技术,以更简单地扩展其行为。
下例中,一个 Modal
组件中分别有 header
、default
和 footer
几个 slots:
<template> <div class="modal"> <slot name="header"> <h2>{{ title }}</h2> </slot> <!-- Default slot for main content --> <slot /> <slot name="footer"> <Button @click="closeModal"> Close </Button> </slot> </div> </template>
例子相当简单,但我们已经有了多种扩展这个组件的选项了:
- 只是覆写
default
slot 来显示内容 - 显示默认内容,并增添
header
slot 部分 - 显示默认内容,并增添
footer
slot 以显示几个按钮 - 显示所有 slots 的内容
6. 嵌套
如果我们将“扩展点”逐层传递,就能达到最终目的。这乍听起来有点繁琐,但确实有用,特别是在大型应用的环境中。
从一个完成相当普通功能的基础组件 A 开始;下一个组件 B 比 A 稍微不那么普通一些,并在很少的方面扩展 A。之后周而复始,直到你拥有了最终能真正工作的组件。
类似于经典的 OOP 例子,我们可以从一个相当通用的 动物
组件扩展到更特别一些的 哺乳动物
,接下来是 狗
并最终得到 贵妇犬
。
要是我们的目的就只是 贵妇犬
,那这一切确实是费了瞎劲;但在大型应用中,我们要从同样但基础想法上扩展出各种各样的结果 -- 比如从 狗
中分化出 金毛
和 京巴
,或从 哺乳动物
中得到 猫科动物
并实现 老虎
和 狮子
。
总结
本文列出了复用 Vue 组件的 6 层手段。这说不上是全部,或许还有其它手段,但已经足够实用了。
✨ 更多“组件化”的文章 ✨
- [译] 状态管理中的第一性原理
- [译] 不用祖传秘方 - 写好代码的几个小技巧
- 用 SOLID 原则保驾 React 组件开发
- 抽丝剥茧 - 实例简析重构代码的三板斧
- [译] 更可靠的 React 组件:单一职责原则
- [译] 更可靠的 React 组件:合理的封装
- [译] 更可靠的 React 组件:组合及可重用性
- [译] 更可靠的 React 组件:提纯
- [译] 更可靠的 React 组件:从"可测试的"到"测试通过的"
- [译] 更可靠的 React 组件:清楚易懂的可表达性