背景
之前二次封装 element 组件时,有些细节处理不到位,没有利用好一些特性,本次针对其中的几个问题作出优化。
问题1
二次封装组件时复用 prop 列表
分析与优化
之前拓展组件时,总是完整地重写一遍 prop 列表,其实没必要。可以直接用 v-bind="$attrs"
替代不需要重写的 prop 。比如:
el-button
/el-link
等组件想使用图标时,必须手动加上前缀el-icon-
,比较繁琐,就将这些部分重写了;并且还老老实实将所有 prop 重写了一遍,因为不写的话,内部的el-button
等组件无法接受到外部传入的 prop 值。
但实际上,除开icon
prop,其他 prop 只需要绑定v-bind="$attrs"
, element 组件就能接收到。之前对于$attrs
的认知错误,以为这个特性只能用于传递 html 元素的自定义属性,其实在这里提到的场景也能使用。此外,vue3 中还将事件监听器也合并到$attrs
,传递起来更加方便。
问题2
减少不必要的组件层级
分析与优化
第二个问题是开发列表组件(比如 cardList
组件用于批量生成卡片,减少重复编写视图结构的工作量)时,总是先把外部组件库的组件封装一层,在此基础上再嵌套一层 list
组件。但其实直接将外部组件库的组件封装到 list
组件里即可,既节省了代码量,同时又减少了文件数量(个人倾向于单文件组件的开发模式),更利于维护项目。
此外,由于舍弃了两层结构,插槽的使用方式也需要调整。
以下使用 el-card
和 card-list
举例。
之前的思路
在el-card
的二次封装组件中定义插槽的出口,并绑定一些 prop ;然后在list
组件中通过“插槽穿透+参数过滤”的方式 (只是个人的命名,非官方;之前写过一篇介绍: 传送门),通过<template>
内部嵌套一层<slot>
的方式,将业务组件传递给list
组件的特定内容,经过card
组件过滤后再批量展示。
比如链接中使用的例子:卡片+行列布局,prop 接收的参数是一个嵌套对象,包含了卡片的参数和布局的参数,每个卡片只会显示自身对象所包含的布局参数,方便批量生成卡片内部的布局。
新的思路将两层结构改为单层结构后,直接在 list
组件内部的 el-card
组件中,定义好插槽出口即可。此处不再需要穿透插槽。
问题3
支持在业务组件中自定义基础组件的样式,或称自定义样式参数
分析与优化
还是拿卡片组件举例,之前将卡片的间距直接写在 list
组件里,不方便动态调整;而如果写在业务组件中,每次都要重写选择器和属性又过于麻烦。因此还是需要基础组件自身有基础样式,同时又必须支持自定义参数。
.dyn-card-list {
.el-card:nth-child(n + 2) {
margin-top: 30px; // 设置除第一个卡片外其他卡片的上间距
}
}
新方案的步骤:
- 通过 prop 传递间距的数值
- 在
el-card
的 style 属性上绑定 css3 的变量(注意此处是 css3 的自定义变量,而非 sass 等预处理器的自定义变量):
<!-- 此处省略了其他 prop -->
<el-card :style="cardGap ? { '--cardGap': cardGap + 'px' } : ''">...</el-card>
...
props: {
...
cardGap: {
type: Number,
default: 0,
},
}