Skip to content

以下是图片内容的提取与整理,采用清晰的 Markdown 排版:


3. 组件设计需要考虑那些?

封装一个公共组件时,主要需要考虑以下几点:

1. 通用性

  • 组件的设计需要足够细致,保证在不同场景下都能通用。
  • 提炼核心功能,避免组件过于特定于某个业务场景。

2. 清晰的 API 设计

  • 定义明确的 props、事件、插槽等接口,让其他团队成员可以快速理解每个参数的用意。
  • 考虑默认值、类型校验和必要的错误提示,降低使用难度。

3. 可定制性

  • 提供简洁的扩展接口或者通过样式、插槽等方式允许自定义内部行为和样式。
  • 保证在不修改组件内部实现的前提下,实现自定义效果。

4. 内部逻辑和状态管理

  • 尽量将组件内部的状态和逻辑封装起来,仅向外暴露必要的接口。
  • 处理好异步数据、事件绑定等问题,防止组件过于臃肿。

5. 兼容性与扩展性

  • 考虑到版本更新和未来扩展,设计时尽量减少对外部组件的依赖或者耦合。
  • 通过合理的封装模式,方便后续维护和升级。

6. 性能优化

  • 考虑组件在多次渲染时的性能问题,如合理使用防抖、节流、缓存等。
  • 根据具体需求选择合适的渲染方式,确保组件在复杂场景下依然高效。

7. 可维护性和文档

  • 提供清晰的文档和使用示例,便于团队成员理解组件逻辑和调用方式。
  • 定期整理代码和注释,确保组件在多人协作环境下易于维护。

4. 二次封装组件需要考虑那些?

二次封装第三方组件库的组件,需要在原有的组件设计层面增加许多考虑:

1. 如何将所有的属性和事件传递给第三方组件?

  • 此处可以使用 $attrs 将属性穿透给子组件,它包含了所有 props 中未声明的属性和事件。
  • 如果需要类型提示,则可以看一下第三方组件库有没有提供类型声明的方式。

2. 如何将插槽传递给第三方组件?

基本上有两种方式,一种是通过循环的方式遍历所有插槽传递给子组件;另一种是使用 h 函数渲染插槽:

vue
<template>
  <component :is="h(AInput, $attrs, $slots)"></component>
</template>

代码逻辑解释:

  • 通过 component 动态组件渲染,这里使用 h 函数创建一个 vnode。
  • h 函数第一个参数是 AInput,表示要渲染 AInput 组件。
  • h 函数第二个参数是 $attrs,表示将所有的属性穿透给 AInput
  • h 函数第三个参数是插槽($slots),表示将当前组件接收到的所有插槽传递给子组件。

这样就很简单地完成了插槽穿透,同时也会将属性一并传递过去。

3. 如何将子组件暴露的方法全部暴露出去?

比较传统的方案是绑定一个 ref 给子组件,然后在组件挂载完成后遍历子组件的 ref,将子组件暴露的方法传递出去。这种方案不太稳定,因为当子组件存在 v-if 时,后续可能会被销毁,导致 ref 依然保留引用,出现内存泄漏。

更好的方式是利用 defineExpose 的原理:defineExpose 会把接收到的对象放到 instance.exposed 上面。

javascript
const instance = getCurrentInstance()

function fn() {
  console.log('暴露fn方法给父组件')
}

defineExpose({
  fn
})

// 等同于以下代码
instance.exposed = { fn }

因此,我们可以给 Component 的 ref 传递一个函数。当组件挂载时,子组件的实例会通过这个函数传递过来:

vue
<template>
  <div>
    <div>自己写的内容</div>
    <component :is="h(ElInput, { ...$attrs, ref: changeRef }, $slots)"></component>
  </div>
</template>

<script setup>
import { ElInput } from 'element-plus'
import { getCurrentInstance, h } from 'vue'

const instance = getCurrentInstance()

function changeRef(exposed) {
  // 这样就相当于 defineExpose(exposed)
  instance.exposed = exposed
}
</script>

通过这种方式,可以避免子组件销毁时所带来的副作用问题。

Released under the MIT License.