引
我们都知道,前端开发时使用组件库可以大大提升我们的开发效率,不用重复造轮子。
但各大组件库间风格样式不尽相同,且常常与我们真实需要的样式不一。
以element-plus为例,在实际使用中我们常常要复写其样式。
方案一:全局样式导入
全局创建一份样式文件,在样式文件上定义覆写的class,将该样式文件在全局导入,在需要覆盖样式的场景将class加上即可:
less
// 重写样式,在使用时将class指定上
.el-input--normal {
// xxx
// 子样式,应对不同场景
&.dark {
// xxx
}
&.width-auto {
// xxx
}
}
// 大瓶界面内的输入框
.el-input--dashboard {
// xxx
}
// 或直接暴力重写(直接.el-dialog,影响所有的el-dialog样式)
.el-dialog {
// xxx
}
缺点:
- 有时候记不住class名,要反复查看该文件,尤其是还带有子class时
- 样式是个性化了,但使用组件时除去要手动指定class外,还需要根据情况指定props属性。例如我希望el-input默认clearable为true,这是使用class做不到的
方案二:自定义组件 包装 组件库组件
为了让el-input默认clearable为true而使用,如果组件库没有提供其全局个性化配置,我们可以自己写个组件将其封装一层,指定好默认属性和样式覆盖:
vue
<script setup lang="ts">
import type { InputProps } from "element-plus";
import { ElInput } from "element-plus";
defineProps<InputProps>();
</script>
<template>
<el-input class="my-input" :="$props" clearable />
</template>
<style scoped>
.el-input.my-input {
/* 在此覆盖样式 */
}
</style>
缺点:
- 每个组件都要自己写一个组件去封装,名字也不能相同
- 样式和属性是可以个性化了,但对于事件只能一个一个手写emit和@xxx去继承,劝退!
方案三:一个自定义组件包装
于是,最终解决方案出现了,我们只需要封装一个自定义组件,将所有用到的默认属性和class写好,通过自定义组件传入的参数不同,应用不同的默认属性与class,全自动!且带有类型提示!
vue
<script setup lang="ts" generic="T extends 'el-input--dashboard' | 'el-dialog--normal'">
import type { DialogProps } from "element-plus";
import type { HTMLAttributes, ReservedProps } from "vue";
type Subtype = {
"el-dialog--normal":
| "body-p-0"
| "width-l"
| "width-m"
| "width-s"
| "width-xs"
| "height-l"
| "height-m"
| "height-s"
| "height-xs";
"el-input--dashboard": "";
}[T];
const { type, subtype = [] } = defineProps<{
type: T;
subtype?: Subtype | Subtype[];
}>();
// 随着type的增多,该文件会越来越大,建议抽离出去保存到任意.ts中,再import进来
const map = {
"el-dialog--normal": {
draggable: true,
alignCenter: true,
closeOnClickModal: false,
destroyOnClose: true,
} as Partial<DialogProps> & HTMLAttributes & ReservedProps,
"el-input--dashboard: {
clearable: true,
},
}
const data = computed<Record<string, any>>(() => map[type] || {});
</script>
<template>
<slot :class="[type, ...(Array.isArray(subtype) ? subtype : [subtype])]" :="data" />
</template>
<style lang="less">
.el-dialog--normal.el-dialog {
--el-dialog-padding-primary: 0;
&.body-p-0 {
.el-dialog__body {
padding: 0;
}
}
}
.el-input--dashboard {
background-color: red;
}
</style>
使用时该组件作为父组件,指定好type和subtype后,通过默认插槽取出默认属性,将其附加给目标组件,即可使用:
vue
<wrapable type="el-dialog--normal" subtype="width-xs" #="attrs">
<el-dialog v-model="show" :="attrs" title="Hello">
<h1>Hello World !</h1>
</el-dialog>
</wrapable>
缺点:
- 想要爽用类型,前提是你要多花时间去定义它,唯一的缺点就是繁琐的前期定义
总结
以上是我在工作中,对个性化组件问题的三种解决方案,希望能够帮到你。
Comments | 0条评论