[译] 复用 Vue 组件的 6 层手段

3,384 阅读4分钟

原文:michaelnthiessen.com/6-levels-of…

在编写代码的时候,谁都想“少干活、多办事”。以组件而言,我们希望它能被不止一次地复用。

一些组件仅需基本的复用性。

另一些则需要更复杂的技术以充分利用。

我认为复用性有 6 中不同的层级,这里大体上来看一下:

1. 模版化

不同于将代码随处复制/粘贴的是,借助模版化可以将其包裹在组件内部。

当复用组件 -- 而不是直接拷贝代码时,给我们带来了两个好处:

  1. 未来的改动变得简单的多,因为只需要在一处进行
  2. 无需再记住类似代码被拷贝到的哪几个甚至上百个地方了

这简直太基础了,也是谈及复用性时最常被说起的。

更高一个层级的就有意思些了:

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>

这样一来,就不受制于传递一个 stringnumber 还是别的什么了。

如果要增加一个 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 组件中分别有 headerdefaultfooter 几个 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>

例子相当简单,但我们已经有了多种扩展这个组件的选项了:

  1. 只是覆写 default slot 来显示内容
  2. 显示默认内容,并增添 header slot 部分
  3. 显示默认内容,并增添 footer slot 以显示几个按钮
  4. 显示所有 slots 的内容

6. 嵌套

如果我们将“扩展点”逐层传递,就能达到最终目的。这乍听起来有点繁琐,但确实有用,特别是在大型应用的环境中。

从一个完成相当普通功能的基础组件 A 开始;下一个组件 B 比 A 稍微不那么普通一些,并在很少的方面扩展 A。之后周而复始,直到你拥有了最终能真正工作的组件。

类似于经典的 OOP 例子,我们可以从一个相当通用的 动物 组件扩展到更特别一些的 哺乳动物,接下来是 并最终得到 贵妇犬

要是我们的目的就只是 贵妇犬,那这一切确实是费了瞎劲;但在大型应用中,我们要从同样但基础想法上扩展出各种各样的结果 -- 比如从 中分化出 金毛京巴,或从 哺乳动物 中得到 猫科动物 并实现 老虎狮子

总结

本文列出了复用 Vue 组件的 6 层手段。这说不上是全部,或许还有其它手段,但已经足够实用了。

✨ 更多“组件化”的文章 ✨



--End--

查看更多前端好文
请搜索 fewelife 关注公众号

转载请注明出处