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 order to improve the overall aesthetics of the project, we usually do not directly use third-party component libraries as they are. We will modify them to better fit 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 the third-party component library is called secondary encapsulation
.
Benefits of Secondary Encapsulation#
- More concise code
- Easier project maintenance
- Stronger component reusability
Introduction to Unocss#
Since we want 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 article on reimagining atomic CSS, and I strongly recommend reading this article before continuing. It will give you a deeper understanding of atomic CSS
. In summary, according to the words of the master:
Atomic CSS is an architectural approach to CSS that tends to use small and 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 functions can be provided through presets and inline configurations
.
Advantages of Unocss#
- Flexibility (property mode, tens of 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 to combine these two things. Here, we will take the loading component
of element plus
as an example to demonstrate 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 version 2 has been directly removed, and its functionality has been merged into $attrs
. For example, when writing a click event, in the 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 we need to 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 link to configure it. The following is the focus.
Secondary Encapsulation#
Here, we choose the loading
component 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 modifications 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 point, we find that the click me
button seems lifeless and does not make people want to click it at all. So, how can we make this button look more appealing 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 appealing, we can try adding a jumping animation to the click me
text. At this time, we open the UnoCSS
playground
and find that the official demo already has a bouncing style. We can directly copy it and modify our child component:
<div class="
text-5xl
fw300
animate-bounce-alt
animate-count-infinite
animate-duration-1s"
>
click me
</div>
At this time, we feel that the default font color of the button seems to be too dark. We can further 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 is, we can download a UnoCSS plugin, search for it directly in vscode, and install it. Then, it will display the source code of this class when placed on it, which is convenient for subsequent development.
Alright, 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 the characteristics of its own 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 too!" 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 😽