Vue2也能用UnoCSS?Vue2+Vite+UnoCSS开发尝试🚀

2,309 阅读6分钟

「本文已参与低调务实优秀中国好青年前端社群的写作活动」

前言

UnoCSS刚发布了0.37,4月份也上线了官方文档。

对UnoCSS有了解,但一直没有尝试,下面就尝试用Vue2+Vite+UnoCSS开发一个页面。

我司目前的项目都是Vue2.x,好在UnoCSS不限制Vue版本,2和3都能用。

image-20220522151157466.png

目录

一、UnoCSS是什么

二、UnoCSS的优势

三、创建Vue2工程

四、添加vue全家桶

五、添加UnoCSS

六、UnoCSS预设

七、愉快的编码


先看一下最终效果

效果.gif

一、UnoCSS是什么

说到UnoCSS就不得不提到作者, Anthony Fu

如果用一句话形容他,只能是“高产似母猪”😜

其本人是许多知名开源项目的代码贡献者,github排名前一百的男人💪

image-20220522152928844.png

UnoCSS是 原子化CSS 的CSS引擎

诞生故事在这里👉 什么是原子化 CSS?

🌰 举个栗子

<!--...省略样式-->

<!--非原子化-->
<button class="juejin-btn">掘金</button>

<!--原子化-->
<button class="bg-blue-500 text-2xl color-white p-10 rounded">掘金</button>

这就是用原子化CSS写出的按钮

image-20220522155911350.png

二、UnoCSS的优势

Tailwind CSSWindiCSS 同属原子化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` })]
]

其他优势,在作者博客上有详细介绍

什么是原子化 CSS?

最吸引我的功能是 属性模式,比Tailwind CSS 写出来的一大串class强太多了

三、创建Vue2工程

UnoCSS 需要运行在 Vite 上,尽管有webpack的插件,但功能少的可怜,不推荐

Vite 创建工程默认是Vue3,先用Vite创建工程,然后修改成Vue2可用

3.1 新建项目

使用npm创建名为vue2unocss的项目

npm create vite

image-20220522165426912.png

修改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

image-20220522180604434.png

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

image-20220522201123157.png

添加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 创建的一致即可

image-20220522212144083.png

路由定义文件

  • 文件名 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>

看下效果

切换路由.gif

4.2 添加Vuex

vuex 同理,步骤与Vue Router一样,就不罗列了。

💥 注意vuex的版本!

  1. 添加npm包
  2. 创建文件
  3. 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的icon的预设,提供了十万个(你没有看错)来自NPM,github,Packagist上的开源图标。

图标来自这里👉 iconify.design

图标完整列表👉 icon-sets.iconify.design

6.1 添加预设

官方预设不用安装npm包,在Vite中配置好就能直接使用

官方预设的名字需要去掉- 并改为驼峰命名

就像这样:@unocss/preset-attributify -> presetAttributify

💥 注意

  • 当添加预设时,默认预设(preset-uno)会被覆盖,所以需要手动添加上
  • 当前版本中默认预设 = preset-wind,所以tailwindCSS的类名开箱即用

下面就装一下属性模式icons预设

关于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包

  1. icon-sets.iconify.design 上查看要安装的包

    image-20220528225605577.png

  2. 下面我装一下Bootstrap Icons,包名是 bi

    从哪里找包名?

    随便点开一个图标冒号前的就是包名

    image-20220528230104953.png

  3. 命令

    npm i -D @iconify-json/包名

    npm i -D @iconify-json/bi
    

6.3 配置icon样式

icon装完以后默认是块级元素,一个占一行。并且只能使用块级元素标签

image-20220528232910287.png

需要修改一下配置,做成行内元素

修改vite配置

  • 文件名 vite.config.js
  • 位置 /vite.config.js
// ……省略
Unocss({
      presets: [
        presetUno(),
        presetAttributify(),
        // 注意下面的部分
        presetIcons({
          extraProperties: {
            display: 'inline-block',
            'vertical-align': 'middle'
          }
        })
      ]
    })

image-20220528233021372.png

6.4 icon如何使用

🌰 举个栗子

苹果图标 👉 icon-sets.iconify.design/bi/apple/

image-20220529095046837.png

类名格式

i- 包名- 图标名

图标名字是 bi:apple,在项目中这么写

<i class="i-bi-apple" />

image-20220529095253696.png

💥只有安装了icon包才能使用对应图标哦

七、愉快的编码

7.1 文档

前面添加了默认预设,可以直接使用tailwindcss的类名

tailwindcss文档 👉 tailwindcss.com

UnoCSS文档 👉 uno.antfu.me

在UnoCSS官网搜索便可查找支持的类名,比如圆角大小,搜索 rounded

我建议看tailwindcss的文档,更直观一些

image-20220529180838057.png

7.2 编写页面

7.2.1 home页面

用tailwindcss的样式实现下面的效果,用到两个Unocss的特性

  1. 属性模式
  2. 省略class

image-20220531145754482.png

修改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'
        }
    ]
})

image-20220531151732149.png

修改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开发的痛点都被作者解决掉了,但在大规模的开发中如何与设计系统配合、怎样复用值得继续探讨。

效果.gif