Skip to content

组件封装原则

常见目录设计

  • components 内部目录结构
    • dialog 对话框
    • loading 加载
    • searchContent 搜索表单
    • table 表格

设计前思考

  • 样式
    • 组件内该写哪些样式、注意什么?
      • 子组件可以先预制一些类,之后传类名即可。
      • 子组件的样式权重设置低一点,方便引用的之后覆盖,避免使用 important
  • template
    • slot 里还是组件里?
      • [[固定内容]]可以写死,不确定的通过 slot 传递,也要考虑数据传递
      • 可以预先设定内容,判断有没有传 slot,优先使用 slot 的值
  • 行为
    • 在父组件定义、还是子组件定义?
      • 基本行为 → 子组件操作(关闭、重置按钮等)
      • 业务行为 → 让父组件监听,再执行相应的操作
    • 还能根据 状态前中后 细分,使这个 组件扩展性 更强
      • 例如:搜索前、中、后;关闭弹框前、后 [[组件行为扩展示例代码]]
  • props
    • 哪些值通过 props 传递,哪些由子组件自己声明?
      • 子组件内部定义、行为越少,扩展性就越好,通过 props 传值扩展性会更强
  • 扩展性 && 便捷性 权衡
    • 组件通过父传值扩展性就会越强
    • 子组件 内部定义 的东西越多,便捷性 就越强
    • 所以引用的地方越多,组件内部行为就应该少一些,多让父组件去执行相应的操作

封装业务组件的 2大原则

不结合具体业务逻辑

  • 数据:一般组件只是最为一个容器,由父组件传入。
  • 操作:子组件负责一些 UI 操作,然后触发父组件的监听,交由父组件进行功能操作。 尽量提供简便
  • 让通用性高的子组件易于使用,如有少量差距,做针对性扩展。

组件数据 2种设计方式

  • 配置项 (props)
  • [[插槽]]

配置项

  • 场景:频繁使用的用配置项
  • 优点:使用者更方便
  • 缺点:
    • 不适用于复杂情况
    • 健壮性差
      • 避免:少传、多传、传错等情况
      • 解决:必须要规范使用者传值,并给出引导、提示(这就是 TS 的必要性)

插槽

  • 场景:自定义插槽用于扩展复杂的、不常用的组件
  • 优点:完全开放,适用于任意情况。
  • 缺点:基础的配置需要使用者写一遍

数据流 原则-建议

  1. 优先使用 computed,警惕 watch / watchEffect 等 API 的使用。转换思维先从克制使用 watch 开始。
  2. 适当使用 readonly, 禁止状态被坏人修改
  3. 最小化状态。避免创建‘缓存’状态,让数据自然流动,不要阻断。
  4. 自顶而下,将细节/副作用分流到 hooks 或子组件中,起一个好一点的名字, 让流程看起来更清晰
  5. 将 watch 转换为 computed 的语义。外观上的差别是 watch 有 callback, 而 computed 是「管道」,会衍生新的数据。比如上面 useRequest 的例子
  6. 推荐使用 VueUse
  7. 封装 hooks, 让各种外部的状态或副作用优雅地集成进来
  8. 单向数据流,对这个有两层理解
    • 表示是一种数据流动的方向,通常和 CQRS 模式配合,比如 Redux、Vuex,只能单向的修改和查询
    • 表示一种数据管辖的范围。 通常应用只有数据的拥有者才有权限变更。进一步地讲,我们应该以组件为边界,来限定数据的管辖范围。需要变更时,通过‘事件’ 来通知拥有者。比如 严格遵循 v-model 协议。
  9. 使用响应式开发思维,构造单向的数据流
    • 尽量管道化的方式去设计你的程序
    • 声明式,不要命令式
    • 拆分组件或 hooks 来分治数据流
    • 组件之间 props 传递也属于数据流。
  10. 使用 ref/reactive → computed → watch → handler → render 这样的顺序组织代码

组件封装-常用属性

  1. $attrs 简化多层组件之间 props 传值
  2. $listeners 简化多层组件之间事件传递
  3. $Slots 更多拓展自定义组件传值,包括自定义 html 元素,及对象;
  4. props validator 增强组件传值稳健性,可自定义业务代码效验参数;
  5. $refs 对外提供 API 增强组件灵活度和可控性;

form 表单组件封装

  • 普通表单
    • 通过组件组合生成的表单
  • 动态表单 [[动态表单]]
    • 通过配置代码生成的表单

生成动态表单的配置代码,一般来说会存储在后端,并通过 API 提供给前端使用。

组件设计参考

  • UI设计交互 就好比模块的 import、exports,要保持统一的出口。即统一风格配色,统一交互。
  • 基本功能 就好比模块的基本作用。必须保证基本功能的同时,兼容其他。
  • 业务拓展 就好比模块间的集成,这就要求组件可依耐性低、可拔插集成、高聚低耦合。
  • 性能 要考虑到大量数据或大量计算与 GUI 渲染线程互斥导致的性能问题。

疑问

父组件中请求数据好?还是子组件中请求数据好?

1、如果现在有一个父组件,3 个子组件。 每个组件展示的数据不同,有 2 种数据获取方式。 第一种:在父组件中获取所有的数据,然后使用 props 传递给每个子组件。 第二种:各个子组件中获取各自的数据。

[!question] 你觉得哪种好?为什么? 答:根据实际业务来 如果数据其他组件用不到, 那么可以由子组件自己获取 如果数据可能被 同级组件 复用 共享 那么由 父组件统一获取然后分发下去 如果数据可能被 跨级组件 复用 共享 那么你需要 vuex 或者 eventbus 统一分发至不同级别的组件 子组件复用率高耦合性小 则独立获取数据, 子组件如果跟父组件关系紧密则父组件获取数据

心得

要考虑心智成本开发成本
不要大而全,让使用者自己组合;也不要过度封装增加使用成本和维护成本,找好平衡。
准备两个方案,考虑便利性扩展性
少用 v-if,尝试使用动态组件切换
做好传值校验(结合TS)

扩展

组件化开发之如何封装组件 - 掘金

转载或 Copy 请标注本站原文地址