大家好,我是鸽鸽。
前面我们一起从零开始搭建了一个公共组件库,在公司有资源维护的情况下,造轮子无疑是自我提升和刷kpi的好方法。但实际上,封装第三方组件库并添加公司的业务逻辑基本上就够用了。
本篇文章我们在之前的组件库的基础上,封装element-plus的el-input组件,一起了解二次封装的要点和技巧。
相关代码在这 learn-create-compoents-lib/class3,建议搭配食用
系列文章
《搭建vue3 & ts组件库脚手架 - 自己撸组件库篇一》
《组件库版本的管理和发布 - 自己撸组件库篇二》
《在组件库中封装element-plus - 自己撸组件库篇三》
安装element-plus
正常情况下,我们的项目中会安装有自己的element-plus
版本。如果再将element-plus
安装到组件库的话,那么项目安装依赖时会下载多个element-plus
的版本。
实际上我们希望的是组件库能够使用项目的element-plus
版本即可。
在这种情况下可以使用package.json
的peerDependencies
来声明外部依赖。
我们在组件库的 package.json
里添加声明
json
// /packages/components/package.json
{
"peerDependencies": {
"element-plus": "^2.3.9"
}
}
然后我们在测试项目也就是根目录的package.json
文件中安装element-plus
json
// /package.json
{
"dependencies": {
"@giegie/components": "workspace:*",
"vue": "^3.3.4",
"element-plus": "^2.3.9"
}
}
配置都写好后,使用 pnpm install
进行安装
修改项目打包配置
排除打包依赖
在之前的文章中,我们在打包时排除了vue
依赖。这里也一样,我们要排除element-plus
有关的依赖,在组件库的vite.config.ts
中进行修改
typescript
// /packages/components/vite.config.ts
export default defineConfig(() => {
return {
external: ['vue', 'element-plus', '@element-plus/icons-vue', /\.scss/]
}
})
其中@element-plus/icons-vue
是element-plus
图标相关的依赖
排除掉 scss
是因为我们要在组件中引入element-plus
的样式,但是这个样式也要从外部项目的element-plus
依赖中获取
为什么是scss而不是css呢? 因为在项目内通常会定制化element-plus的样式,这都是通过修改element-plus的scss变量来完成的。如果想定制的样式能影响封装在我们组件库中element-plus组件的话,后面在我们的组件也必须要引入element-plus的scss样式。
自动引入element-plus的样式
在编写我们组件库的组件时,需要使用按需加载的方式引入element-plus
组件,如:
html
<template>
<el-input />
</template>
<script setup lang="ts">
import { ElInput } from 'element-plus'
import 'element-plus/theme-chalk/src/base.scss'
import 'element-plus/theme-chalk/src/input.scss'
</script>
可以看到我们不仅要引入组件,还需要引入基础样式和组件样式,这个需要的element-plus
组件变多的话,非常麻烦。
我们需要使用unplugin-element-plus
帮助我们自动引入样式
安装unplugin-element-plus
到组件库的包下
bash
pnpm add unplugin-element-plus -D --filter components
在vite
配置文件里添加下面配置
typescript
// /packages/components/vite.config.ts
import ElementPlus from 'unplugin-element-plus/vite'
export default defineConfig(() => {
return {
plugins: [
// ...
ElementPlus({
// 导入scss而不是css
useSource: true
}),
]
}
})
配置好后,编写组件时只用向下面这样就行
html
<template>
<el-input />
</template>
<script setup lang="ts">
import { ElInput } from 'element-plus'
</script>
简单封装el-input组件
将之前封装好的gie-input
中的input
换成el-input
组件,功能和之前一样,最终文件如下
html
<template>
<div class="gie-input">
<el-input v-model="state" ref="inputRef" type="text" :disabled="props.disabled" />
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
import { ElInput } from 'element-plus'
import type { InputEmits, InputProps } from './Input';
defineOptions({
name: 'GieInput',
})
const emit = defineEmits<InputEmits>()
const props = withDefaults(defineProps<InputProps>(), {
modelValue: '',
disabled: false
})
const state = computed({
get: () => props.modelValue,
set: (val) => {
emit('update:modelValue', val)
}
})
const inputRef = ref<InstanceType<typeof ElInput>>()
function focus() {
inputRef.value?.focus()
}
defineExpose({
focus
})
</script>
运行打包和预览命令
bash
npm run build
npm run dev
在浏览器中可以看到结果
将组件接入到el-form的表单校验
我们在组件库里封装的组件,大概分为3类。表单组件、数据展示组件和布局组件。
其中表单组件一般都会和element-plus
里的el-form
组件结合使用。假如我们自己封装一个富文本组件,当输入后失去焦点且字段要求必填时,会自动触发el-form
的校验。此时需要显示错误提示和我们自己封装的富文本的边框变红,这应该如何实现呢?
首先我们需要在组件里获取到el-form-item
组件的实例,element-plus
暴露了一个contextKey
,可以让我们方便的将el-form-item
实例注入进来:
html
<script setup lang="ts">
import { formItemContextKey } from 'element-plus'
const elFormItem = inject(formItemContextKey)
</script>
然后通过元素的blur
事件调用校验方法:
html
<template>
<div contenteditable="true" @blur="onBlur"></div>
</template>
<script setup lang="ts">
import { formItemContextKey } from 'element-plus'
const elFormItem = inject(formItemContextKey)
const onBlur = () => {
elFormItem!.validate?.('blur').catch((err) => console.warn(err))
}
</script>
可以看到上面validate
方法的参数为blur
,这个表示执行项目中规则的trigger
为blur
的校验。
typescript
const rules = reactive<FormRules<RuleForm>>({
test: [
{ required: true, message: '请输入文字', trigger: 'blur' },
]
})
到这里错误提示可以在失去焦点并校验失败时自动显示出来,下面开始修改错误时的边框样式。
可以看到,当校验失败时,el-form-item
上会加上is-error
的class
,我们只用通过class
来修改边框即可
scss
.gie-richtext{
flex: 1;
&__control{
border: 1px solid #aaa;
background: #eee;
border-radius: 5px;
padding: 16px;
min-height: 100px;
.is-error & {
border-color: red;
}
}
}
总结
本篇文章学习了通过peerDependencies
安装element-plus
,并在打包时将element-plus
相关的包排除在外。封装element-plus
,以及和el-form
校验相结合。
到这里基本上组件库封装element-plus就完成了,以后再复杂的组件也只需要在这套脚手架项目上添砖加瓦即可。
以后有好的组件库编写技巧的话会继续分享的咕!