「本文已参与低调务实优秀中国好青年前端社群的写作活动」
前言
UnoCSS刚发布了0.37
,4月份也上线了官方文档。
对UnoCSS有了解,但一直没有尝试,下面就尝试用Vue2+Vite+UnoCSS开发一个页面。
我司目前的项目都是Vue2.x,好在UnoCSS不限制Vue版本,2和3都能用。
目录
一、UnoCSS是什么
二、UnoCSS的优势
三、创建Vue2工程
四、添加vue全家桶
五、添加UnoCSS
六、UnoCSS预设
七、愉快的编码
先看一下最终效果
一、UnoCSS是什么
说到UnoCSS就不得不提到作者, Anthony Fu
如果用一句话形容他,只能是“高产似母猪”😜
其本人是许多知名开源项目的代码贡献者,github排名前一百的男人💪
UnoCSS是 原子化CSS 的CSS引擎
诞生故事在这里👉 什么是原子化 CSS?
🌰 举个栗子
<!--...省略样式-->
<!--非原子化-->
<button class="juejin-btn">掘金</button>
<!--原子化-->
<button class="bg-blue-500 text-2xl color-white p-10 rounded">掘金</button>
这就是用原子化CSS写出的按钮
二、UnoCSS的优势
Tailwind CSS
和 WindiCSS
同属原子化CSS的框架,而且开源的更早,社区也很庞大
跟他们比 UnoCSS
好在哪里?
1. 编译速度快
github中 提到 Tailwind 3.0 的编译耗时是UnoCSS的187倍,足以证明UnoCSS有多快
3/26/2022, 11:41:26 PM
1656 utilities | x50 runs (min build time)
none 12.42 ms / delta. 0.00 ms
unocss v0.30.6 20.98 ms / delta. 8.57 ms (x1.00)
tailwindcss v3.0.23 1621.38 ms / delta. 1608.96 ms (x187.79)
windicss v3.5.1 1855.86 ms / delta. 1843.45 ms (x215.16)
2. 兼容性好
通过添加预设,可以支持Tailwind CSS的类名
3. 属性模式
使用原子化CSS有一个通病:class巨长,html的可读性下降不少
<!-- class -->
<button class="bg-blue-500 text-2xl color-white p-10 rounded">掘金</button>
使用属性模式后,代码可读性成倍提高
<!-- 属性 -->
<button
bg="blue-500"
text="2xl white"
font="mono light"
p="10"
border="rounded"
>
掘金
</button>
在 7.2.2 中提到了捷径配置,能更近一步化简
4. 省略class
除了属性模式外,Uno CSS还支持省略class
<!-- 无class -->
<button bg-blue-500 text-2xl color-white p-10 rounded>掘金</button>
5. 可定制
支持用正则定义class
比如需要调整margin的类名 m-1
m-2
m-3
....,可以用正则实现,节省花在配置上的时间
rules: [
[/^m-(\d+)$/, ([, d]) => ({ margin: `${d / 4}rem` })]
]
其他优势,在作者博客上有详细介绍
最吸引我的功能是 属性模式,比Tailwind CSS 写出来的一大串class强太多了
三、创建Vue2工程
UnoCSS 需要运行在 Vite
上,尽管有webpack的插件,但功能少的可怜,不推荐
Vite
创建工程默认是Vue3,先用Vite创建工程,然后修改成Vue2可用
3.1 新建项目
使用npm创建名为vue2unocss
的项目
npm create vite
修改vue版本
cd vue2unocss
npm i vue@2
安装vue2必须插件
npm i vue-template-compiler vite-plugin-vue2 -D
删除vue3插件
npm uninstall @vitejs/plugin-vue
3.2 修改文件
vite配置
-
文件名
vite.config.js
-
位置
/vite.config.js
配置别名和端口号
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import path from 'path'
function resolve(dir) {
return path.join(__dirname, dir)
}
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 8080,
hmr: true //热更新
},
resolve: {
alias: {
'@': resolve('src')
}
},
plugins: [
createVuePlugin()
]
})
主入口
-
文件名
main.js
-
位置
/src/main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
主组件
-
文件名
App.vue
-
位置
/src/App.vue
<template>
<div>
<img alt="Vue logo" src="@/assets/logo.png" />
<h1>Vue2 + Vite + Unocss</h1>
</div>
</template>
到这里项目已经能运行了 npm run dev
3.3 添加eslint
光能运行还不够,下面配置一下代码检查 eslint
你可以使用
eslint --init
按提示创建如果按以下命令创建,使用的是
standard
安装vite插件
npm install vite-plugin-eslint eslint-plugin-html -D
安装eslint插件
npm install -D eslint \
eslint-config-standard \
eslint-plugin-vue \
eslint-plugin-promise \
eslint-plugin-n \
eslint-plugin-import
vite添加插件
-
文件名
vite.config.js
-
位置
/vite.config.js
// ……省略
import eslint from 'vite-plugin-eslint'
export default defineConfig({
// ……省略
plugins: [
createVuePlugin(),
eslint()
]
})
💥 VS Code配置注意检查是否开启.vue文件文件验证
{ "eslint.probe": ["javascript", "vue", "html"] }
创建eslint配置文件
-
文件名
.eslintrc.js
-
位置
/.eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:vue/strongly-recommended',
'standard'
],
parserOptions: {
ecmaVersion: 13,
sourceType: 'module'
},
plugins: [
'vue'
],
rules: {
'space-before-function-paren': 0,
'vue/max-attributes-per-line': ['error', {
singleline: {
max: 5
},
multiline: {
max: 1
}
}]
}
}
看下效果,eslint报错时会在浏览器中显示
如果命令窗口显示报错,浏览器中缺显示空白画面,尝试清空缓存并重启
Vite
添加lint
命令
-
文件名
package.json
-
位置
/package.json
{
"scripts": {
// ...省略
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
}
到这一步,完整的package.json如下
{
"name": "vue2unocss",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
"dependencies": {
"vue": "^2.6.14"
},
"devDependencies": {
"eslint": "^8.16.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-vue": "^9.0.1",
"vite": "^2.9.9",
"vite-plugin-eslint": "^1.6.1",
"vite-plugin-vue2": "^2.0.1",
"vue-template-compiler": "^2.6.14"
}
}
四、添加vue全家桶
上面的步骤已经可以安装 UnoCSS
了,在实际开发中还会用到 Vue Router、Vuex 在这里一块添加处理
可以跳过这一步直接装
UnoCSS
4.1 添加Vue Router
安装 vue-router
npm install vue-router@3
router目录结构和用Vue Cli 创建的一致即可
路由定义文件
-
文件名
index.js
-
位置
/src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
// 注册路由插件
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: () => import('@/views/HomeView.vue')
},
{
path: '/about',
name: 'About',
component: () => import('../views/AboutView.vue')
}
]
const router = new VueRouter({
routes,
mode: 'history'
})
export default router
首页
-
文件名
HomeView.vue
-
位置
/src/views/HomeView.vue
<template>
<div>
<h1>HOME</h1>
</div>
</template>
<script>
export default {
name: 'HomeView'
}
</script>
关于页
-
文件名
AboutView.vue
-
位置
/src/views/AboutView.vue
<template>
<div>
<h1>这是关于页面</h1>
</div>
</template>
<script>
export default {
name: 'AboutView'
}
</script>
在main.js中引入router
-
文件名
main.js
-
位置
/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
router,
render: h => h(App)
}).$mount('#app')
修改App.vue
-
文件名
App.vue
-
位置
/src/App.vue
<template>
<div>
<div>
<router-link to="/">
home
</router-link>
<router-link to="about">
about
</router-link>
</div>
<router-view />
</div>
</template>
看下效果
4.2 添加Vuex
vuex 同理,步骤与Vue Router一样,就不罗列了。
💥 注意vuex的版本!
- 添加npm包
- 创建文件
- main.js增加引用
五、添加UnoCSS
安装包
npm i -D unocss
修改vite配置
-
文件名
vite.config.js
-
位置
/vite.config.js
// ……省略
import Unocss from 'unocss/vite'
export default defineConfig({
// ……省略
plugins: [
createVuePlugin(),
eslint(),
Unocss()
]
})
在main.js中引用UnooCSS
-
文件名
main.js
-
位置
/main.js
// ……省略
import 'uno.css'
// ……省略
六、UnoCSS预设
理解为UnoCSS的插件,在 二、UnoCSS的优势
中提到的属性模式,就需要添加预设后才能用
官方提供的几个预设
- @unocss/preset-uno - 默认预设(现在相当于
@unocss/preset-wind
)。 - @unocss/preset-mini - 最小预设。
- @unocss/preset-wind - Tailwind / Windi CSS 紧凑预设。
- @unocss/preset-attributify -为其他预设和规则提供属性模式。
- @unocss/preset-icons - 使用任何图标作为类实用程序。
- @unocss/preset-web-fonts - 轻松使用 Web 字体。
- @unocss/preset-typography - 排版预设。
提别提一下UnoCSS的icon的预设,提供了十万个(你没有看错)来自NPM,github,Packagist上的开源图标。
图标来自这里👉 iconify.design
图标完整列表👉 icon-sets.iconify.design
6.1 添加预设
官方预设不用安装npm包,在Vite中配置好就能直接使用
官方预设的名字需要去掉-
并改为驼峰命名
就像这样:@unocss/preset-attributify -> presetAttributify
💥 注意
- 当添加预设时,默认预设(preset-uno)会被覆盖,所以需要手动添加上
- 当前版本中默认预设 =
preset-wind
,所以tailwindCSS的类名开箱即用
下面就装一下属性模式
和icons
预设
修改vite配置
- 文件名
vite.config.js
- 位置
/vite.config.js
// ……省略
import { presetUno, presetAttributify, presetIcons } from 'unocss'
// ……省略
plugins: [
createVuePlugin(),
eslint(),
// 注意下面的部分
Unocss({
presets: [
presetUno(),
presetAttributify(),
presetIcons()
]
})
]
6.2 安装icon包
icon预设添加完后,要安装一下icon包
-
在 icon-sets.iconify.design 上查看要安装的包
-
下面我装一下
Bootstrap Icons
,包名是 bi从哪里找包名?
随便点开一个图标冒号前的就是包名
-
命令
npm i -D @iconify-json/
包名
npm i -D @iconify-json/bi
6.3 配置icon样式
icon装完以后默认是块级元素,一个占一行。并且只能使用块级元素标签
需要修改一下配置,做成行内元素
修改vite配置
- 文件名
vite.config.js
- 位置
/vite.config.js
// ……省略
Unocss({
presets: [
presetUno(),
presetAttributify(),
// 注意下面的部分
presetIcons({
extraProperties: {
display: 'inline-block',
'vertical-align': 'middle'
}
})
]
})
6.4 icon如何使用
🌰 举个栗子
苹果图标 👉 icon-sets.iconify.design/bi/apple/
类名格式
i-
包名-
图标名
图标名字是 bi:apple
,在项目中这么写
<i class="i-bi-apple" />
💥只有安装了icon包才能使用对应图标哦
七、愉快的编码
7.1 文档
前面添加了默认预设,可以直接使用tailwindcss的类名
tailwindcss文档 👉 tailwindcss.com
UnoCSS文档 👉 uno.antfu.me
在UnoCSS官网搜索便可查找支持的类名,比如圆角大小,搜索 rounded
我建议看tailwindcss的文档,更直观一些
7.2 编写页面
7.2.1 home页面
用tailwindcss的样式实现下面的效果,用到两个Unocss的特性
- 属性模式
- 省略class
修改HomeView.vue
- 文件名
HomeView.vue
- 位置
/src/views/HomeView.vue
<template>
<div max-w-2xl mx-auto>
<div flex bg-blue-500 text-white p-16 rounded-xl shadow="2xl blue-500/50">
<div>
<h1>Hi,Maokai</h1>
<p>我朋友说再当舔狗就打断我的腿,幸好是腿,要是手的话,就没办法和你聊天了,宝。</p>
<a href="https://juejin.cn/user/1838039173968382">
<button rounded-full border-none bg-white p-3 mb-5 shadow="xl indigo-500/50" hover="scale-120 shadow-2xl" transition cursor-pointer>
掘金个人主页
</button>
</a>
<div flex space-x-4>
<i class="i-bi-windows" />
<i class="i-bi-chat-right-dots-fill" />
<i class="i-bi-github" />
</div>
</div>
<div flex items-center>
<div flex w-32 h-32 items-center justify-center rounded-full bg-white shadow="xl indigo-500/50">
<i class="i-bi-person-heart" text="gray 7xl" />
</div>
</div>
</div>
</div>
</template>
7.2.2 about页面
从代码中可以看出,即使有 属性模式 、省略class 这样的特性,写出来的html可读性依旧很差。
托尼大佬也是这么想的,所以 —— WindiCSS
的 捷径 也被加到UnoCSS中了
一堆class定义成一个名字,像这样。在html中只写 btn
就可以了
短小精悍😝
{
'btn': 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700',
}
在 vite配置 中定义捷径
- 文件名
vite.config.js
- 位置
/vite.config.js
// 省略...
Unocss({
// 省略...
shortcuts: [
{
btn: 'py-2 px-4 font-semibold rounded-lg shadow-md',
'btn-green': 'text-white bg-green-500 hover:bg-green-700'
}
]
})
修改AboutView.vue
- 文件名
AboutView.vue
- 位置
/src/views/AboutView.vue
<template>
<div text-center>
<button btn>这是关于页面</button>
<br>
<br>
<button btn-green>这是关于页面</button>
</div>
</template>
7.3 ✨大功告成
Vue2 + Vite + UnoCSS 就结束了
原子化CSS跟常用的BEM命名开发区别还是很大的,各有利弊。
以往很多原子化CSS开发的痛点都被作者解决掉了,但在大规模的开发中如何与设计系统配合、怎样复用值得继续探讨。