Preface#
In daily development, in order to avoid reinventing the wheel and wasting development time, we often use third-party component libraries such as element plus
and vant-ui
. However, in some cases, in order to improve the overall aesthetics of the project, we will not directly use third-party component libraries, but modify them to make them more in line with the overall UI style of the project. At this time, we can extract the third-party component library and package it into a common component library
. This operation of encapsulating third-party component libraries is called secondary encapsulation
.
Benefits of Secondary Encapsulation#
- More concise code
- Easier maintenance in the later stages of the project
- Stronger component reusability
Introduction to Unocss#
Since we are going to encapsulate the original third-party component library, it is inevitable to modify its styles
. Modifying CSS is often the most headache-inducing part (at least for me 🥴). At this time, I saw antfu
's Reimagining Atomic CSS, and I strongly recommend reading this article before continuing, which will give you a deeper understanding of Atomic CSS
. Here is a summary in the words of the master:
Atomic CSS is an architectural approach to CSS that tends to use small, single-purpose classes and names them based on visual effects.
Unocss is the high-performance and highly flexible instant atomic CSS engine
created by antfu. As for why it is an engine rather than a CSS framework, it is because Unocss does not provide any core utility classes, and all functionality can be provided through presets and inline configurations
.
Advantages of Unocss#
- Flexibility (property mode, thousands of
pure CSS icons
, no need to worry about style conflicts) - Strong style reusability
- No need to think about class names! (This is a great help for people who have difficulty naming things) 🤣
Since both secondary encapsulation
and Unocss
can greatly improve development efficiency and make everyone happy, let's try combining these two things together. Here, we will take the loading component
of element plus
for a simple secondary encapsulation, and then use Unocss
to beautify it.
Core of Secondary Encapsulation#
Here, we use the component encapsulation method of vue3
, which is slightly different from the encapsulation method of vue2
. For the encapsulation method of vue2
, please refer to Red Dust's article.
$attrs#
An object containing all the passed-through attributes of the component.
This is the official definition of $attrs
in Vue, which refers to attributes and event handling functions that are passed in by the parent component and are not declared as props or custom events of the child component. For example, when we nest a <button>
inside a <div>
tag in a component, if we want to apply pass-through attributes such as class
or v-on
listeners directly to the inner <button>
, we can use v-bind="$attrs"
to achieve this.
Inheriting v-on Listeners#
In vue3
, the $listeners
event listener in vue2
has been directly removed, and its functionality has been merged into $attrs
. For example, when writing a click event, in component encapsulation, the click of the atomic component will still trigger the onclick event of the parent component.
<!-- Child component -->
<button>click me</button>
<!-- Parent component -->
<MyButton @click="onClick" />
Component Encapsulation#
Project Initialization#
Enter the following command in the command line:
pnpm create vite element-plus-unocss --template vue
Use vite+pnpm
to quickly initialize the project.
cd element-plus-unocss
pnpm i
pnpm run dev
After successful execution, the project initialization is complete.
Importing Component Library#
The component library we want to encapsulate is element plus
, so let's import it:
pnpm install element-plus
Here, we still follow the recommended automatic import by the official website. I won't go into details here. Just click on the official website link for configuration. The following is the focus.
Secondary Encapsulation#
Here, we choose the loading
component of element plus
for demonstration. Add the child component loading.vue
to the components
folder, and directly copy the example from the official link (you can make some deletions if necessary):
<template>
<el-button
v-loading.fullscreen.lock="fullscreenLoading"
type="primary"
@click="openFullScreen1"
>
Click me
</el-button>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElLoading } from 'element-plus'
const fullscreenLoading = ref(false)
const openFullScreen1 = () => {
fullscreenLoading.value = true
setTimeout(() => {
fullscreenLoading.value = false
}, 2000)
}
</script>
Now create the Myloading.vue
component, import it, and modify its code:
<template>
<Loading
v-bind="$attrs"
element-loading-text="Loading~"
element-loading-background="rgba(122, 122, 122, 0.8)"
/>
</template>
<script setup>
import Loading from "./loading.vue";
</script>
<style>
.el-loading-mask .el-loading-spinner .el-loading-text {
font-size: 20px;
}
</style>
The result is as follows:
This means that the secondary encapsulation
of our component is successful.
Beautifying Components with UnoCSS#
At this time, we found that the click me
button seems lifeless and does not make people want to click it. So, what can we do to make this button more eye-catching and make people want to click it? This is where our heavyweight character UnoCSS
comes in.
Installing and Importing UnoCss#
pnpm i -D unocss
Configure vite.config.js
:
import Unocss from 'unocss/vite'
export default {
plugins: [
Unocss({ /* options */ }),
],
}
And import UnoCSS
into main.js
: import 'uno.css'
Configuring Presets#
Configuring presets is an important advantage of UnoCSS
. With just a few simple presets, you can build your own custom framework
in minutes. Attributify
is one of the characteristics of Windi CSS
, which is also retained in UnoCSS
. Here, we install preset-attributify
and unocss/preset-uno
:
pnpm i -D @unocss/preset-attributify
pnpm i -D @unocss/preset-uno
Modified vite.config.js
:
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Unocss from '@unocss/vite'
import presetUno from '@unocss/preset-uno'
import presetAttributify from '@unocss/preset-attributify'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue(), AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
Unocss({
presets: [presetUno(), presetAttributify()]
})
]
})
Now we have a default preset + attribute mode
custom framework. After writing a long string of CSS classes, they will be grouped according to the attribute mode
, making the code more tidy and greatly improving readability:
<button
bg="blue-400 hover:blue-500 dark:blue-500 dark:hover:blue-600"
text="sm white"
font="mono light"
p="y-2 x-4"
border="2 rounded blue-200"
>
Button
</button>
Modifying Component Styles#
In order to make the button look more desirable to click, we can try adding a jumping animation to click me
. At this time, we open the UnoCSS
playground
and find that the official demo already has a bouncing style. Let's copy it and modify our child component:
<div class="
text-5xl
fw300
animate-bounce-alt
animate-count-infinite
animate-duration-1s"
>
click me
</div>
Now we feel that the default button text color seems a bit too dark. At this time, we can modify it in the parent component:
<Loading
element-loading-text="Loading~"
v-bind="$attrs"
element-loading-background="rgba(122, 122, 122, 0.8)"
class="text-lg
fw300
m2
op70"
/>
If we want to know what the
cv
actually means, we can download a UnoCSS plugin, search for it directly in vscode, and after installing it, it will display the source code of this class, which is convenient for subsequent development.
Okay, let's take a look at the appearance of the button after beautification:
Constantly jumping, doesn't it make people want to click it more? 😂
Conclusion#
As a newcomer to atomic CSS, UnoCSS is refreshing. It draws on the advantages of its predecessor taiwind CSS
and incorporates its own characteristics of windiCSS
, making it surprisingly easy to use. Although it is still in the testing phase, I highly recommend everyone to give it a try. It will definitely give you a feeling of "What? You can do this?". You can even use UnoCSS
to build your own component library. Here is a link to my own component library project, which is an attempt with UnoCSS: https://github.com/isolcat/CatIsol-UI
Component library preview address: https://cat-isol-ui.vercel.app 😽