近期在准备搭建一个通用组件库,而公司现有的各个系统也已有自己的组件库只是没抽离出来,但是目前有两套不同的组件封装方案,所以对于方案的选择比较困惑,于是对两种方式进行了对比,结合网上找到的一些开源组件库进行分析。记录一下子叭!~
一、现有系统的组件设计思路
目前,A系统和B系统两个项目中各自有设计自己的组件库,但由于底层封装方案不同,使用时的配置信息也有一些差别,可以通过比较常见的表格、表单组件作为例子直观感受一下。
二、组件封装的方式选择
每个组件都有其特定的属性(props)、插槽(slots)和事件(events),这些构成了组件的 API。
props | 子组件接收的参数,最好用对象的写法,这样可以针对每个属性设置类型、默认值或自定义校验属性的值,还可通过type、validator、required等方式对输入进行验证 |
slot | 可以给子组件的特定位置动态插入一些内容或组件(模板) |
event | 子组件可以通知父组件其内部状态的变化或用户的交互行为,使得父组件可以据此更新状态或执行其他操作(子组件在特定的情况下触发事件,父组件监听这些事件并作出响应) |
组件封装的方式选择
- 第一种,先设置好各种类型的组件,使用v-if逐个判断渲染(例子:A系统)
<el-form-item>
<el-input v-if="item.type == $const.FormCompType.input" />
<el-input-number v-if="item.type == $const.FormCompType.number" />
<slot v-if="item.type == $const.FormCompType.slot" :item="item" :name="item.slotName" />
</el-form-item>
- 第二种,利用vue内置的component组件,直接传入Element UI组件(例子:B系统)
<el-form-item>
<component :is="item.type" />
</el-form-item>
组件封装在实现表单动态渲染、实现表单可视化配置这方面的应用会比较丰富和直观一些,正好以上A系统中就采用了v-if方法,而B系统则采用了内置component的方法。
下面,笔者将通过一个表格,从多个角度分析展示两种方案的区别。
v-if方式 | component方式 | |
封装繁琐程度 | 封装代码冗长 需要全面考虑到各种类型 | 代码简单直接 依靠<component :is="">可以实现任何组件 |
上手难易 | 上手简单 | 需要先学习配置规则 |
可维护性 | 因配置结构扁平而更容易定位一些 | 需要清楚地知道数据结构才能定位 |
配置方式 | 层级较少、集中且直观 但只能使用预先设计好的类型、或者更新丰富组件 | 层级较深、不够直观且容易形成套娃 但可设置的属性更加全面、无需在有新类型时更新组件,只要elementUI有的组件都能直接实现 |
扩展性 | 扩展性较好
| 扩展性有限
|
优势 | 抽象和重用:提供抽象层,代码更清晰可维护,同时提高了组件的重用性 自定义和扩展性:通过type属性可方便地扩展新的控件类型,添加自定义逻辑和样式以满足项目的特定需求 易于管理和维护:方便地调整界面结构和行为,需要修改表单控件时,只需修改相应组件,无需在多个地方更改和修改底层的UI组件库组件 | 灵活性:能够直接利用Element UI提供的丰富组件和特性,无需额外封装,开发效率高 减少封装成本:无需投入时间和资源去封装每个表单控件和处理所有可能的边界情况 与库保持同步:UI组件库通常会持续更新和修复问题,直接使用库中的组件可以确保应用始终获得最新的功能和修复,降低了维护成本 快速集成:直接利用现有的 ElementUI 组件,可以快速集成到项目中,减少开发时间 |
劣势 | 封装成本高:需要投入时间和资源去封装每个表单控件,并确保它们能够正确响应传入的配置 性能损失:可能会导致不必要的渲染和销毁,可能导致一定的性能损失,尤其是在渲染大型表单时。但是这种损失通常是可接受的,可得到优化的 维护性挑战:随着控件类型、数量和复杂度的增加,组件内部逻辑可能会变得复杂,维护起来较为困难 代码冗余:使用 v-if 进行条件渲染可能会导致代码冗余,尤其是在控件类型较多时 | 配置复杂性:对于复杂的表单或界面,直接传入Element UI组件可能需要更复杂的配置和属性管理,增加了开发的复杂性 缺乏抽象层:代码更依赖于特定的库实现,缺乏抽象层,代码结构可能不够清晰和易于维护 更难以定制:封装组件可根据需要添加额外的逻辑或样式来定制组件的行为或外观。对于需要高度定制化的表单控件,直接使用库中的组件可能不够灵活 复用性差:每个表单控件都直接使用ElementUI组件,无法对它们进行统一的封装和扩展 维护成本高:随着组件类型的增加,代码变得难以维护,特别是当需要调整表单控件的样式或行为时,可能需要修改多个地方,维护较为繁琐 |
其它 |
|
|
三、采取折中方式
方案一和方案二都有各自的优势和不足,所以也许将两者综合一下,设计出第三种方案。
①先单独封装好各种类型的表单控件小组件,②再通过<component :is="">来动态渲染,保证高度的组件复用性和扩展性,并避开v-if判断;③对配置的数据结构进行调整使其更扁平化,降低使用门槛并提高开发效率。
此时,整个组件封装的设计思路 be like:
用文字描述上图所示的方案:
①在表单Form 上通过<component :is="">来动态渲染不同类型的表单控件小组件,
②对各种类型的控件进行独立封装、分开管理,并导入和注册
③根据需要,在各个小组件中添加一些自定义属性、样式和其他定制化功能等
优势
▷ 高复用性:通过单独封装各种类型的表单控件小组件,实现了高度的组件复用
▷ 灵活性:通过封装各种表单控件小组件,可以确保每个组件都具备较高的可重用性和可扩展性。同时,使用<component :is="">可以根据配置动态渲染不同的组件,提供了更大的灵活性
▷ 易于维护:每一种特定的表单控件都有独立的封装组件,易于进行单独的维护和测试。每个表单控件都有明确的封装边界(内部实现细节被隐藏起来,只暴露必要的接口供外部使用),这有助于保持代码的模块化和可维护性
▷ 良好的扩展性:添加新的控件类型时,只需要创建新的封装组件并注册到组件库中即可
▷ 数据结构扁平化:通过调整数据结构,使得配置更加扁平、简洁直观和易于管理,更容易理解和操作,降低了使用门槛
潜在问题
▷ 初期投入大:需要投入较多的时间和精力来单独封装各种类型的表单控件小组件
▷ 组件间的耦合度:如果小组件之间的耦合度较高,可能会导致代码难以维护和扩展。因此,在封装组件时需要注意组件的独立性和可重用性
▷ 配置复杂性:虽然通过扁平化数据结构可以简化配置,但如果配置项过多或过于复杂,仍然可能导致配置过程变得繁琐。因此,需要仔细设计配置结构,确保其既简洁又易于理解
需要确保所有可能的组件都已经正确地引用和注册
优化措施
♢ 1. 优化配置结构
○ 减少嵌套层级:将原有的嵌套配置结构扁平化,减少层级深度,使配置更加直观。
○ 使用枚举或常量:对于配置中的某些固定值或选项,使用枚举或常量进行替换,避免硬编码和魔法值。
○ 提供默认值:为配置项提供合理的默认值,减少开发者在配置时的必要输入。
♢ 2. 简化组件接口
○ 明确输入输出:每个小组件应该有清晰的输入(props)和输出(events),避免过多的配置选项和复杂的事件处理。
○ 使用统一的接口规范:确保所有小组件都遵循相同的接口规范,这样开发者在使用时就不需要为不同组件学习不同的配置方式。
♢ 3. 提高组件复用性
○ 使用插槽(Slots):在小组件中预留插槽,允许开发者自定义内容或扩展功能,提高组件的复用性和灵活性。
○ 提供通用功能:对于一些通用的表单控件功能(如验证、格式化等),可以在小组件中统一实现,减少开发者在每个表单字段上的重复工作。还可以预留一些前缀、后缀等配置。
♢ 4. 优化渲染性能
○ 使用v-show代替v-if:对于频繁切换显示/隐藏的场景,使用v-show可以避免不必要的组件销毁和重建,提高渲染性能。
○ 按需加载:如果项目较大,可以考虑使用代码分割和异步组件技术,按需加载需要的表单控件小组件。
♢ 5. 提供示例和文档
○ 编写清晰的文档:为小组件和配置结构提供详细的文档说明,包括输入输出的参数、用法示例、注意事项等。
○ 提供示例代码:为常见使用场景提供示例代码,帮助开发者快速上手和理解如何使用这些小组件和配置。
♢ 6. 进行单元测试和集成测试
○ 编写单元测试:为每个小组件编写单元测试,确保它们的功能正确性和稳定性。
○ 进行集成测试:对整个表单系统的不同配置和组合进行集成测试,确保在各种场景下都能正常工作。