🤔 当强迫症在Uniapp & Vue3中使用UnoCSS

    569

引入方式大同小异,和开发Web项目的方式差不多,但是因为其是小程序,所以还需要进行一些调整

export default defineConfig({
  // ...UnoCSS options
  theme: {
    preflightRoot: ['page,::before,::after']
  }
})

小程序的根节点是 page

0️⃣ 编码习惯 🫠

我通常更倾向于 TailwindCSS 的那种写法,且会对不同类型的Class进行分行

于是我照常将这种写法用于 Uniapp 中,在微信开发者工具中得到了如下结果 ☹️

这里就得提到 Unocss 对于 x-[xx] 的编译结果了

text-[25px]

.text-\[25px\] {
  font-size:25px;
}

结合上述的报错可以发现,是由这里的 \ 所导致

那为了让自己写起来更舒服,于是就开始捣鼓该如何解决了 😋


1️⃣ And

text-[25px] -> text-_25px_

总结就是得让其不在小程序报错,所以需要对不支持的字符进行替换 👀

这里需要干涉 UnoCSS 以及 Vue 的编译

  • UnoCSS:修改其编译结果(Class 名称,让其不在小程序中报错
  • Vue: 还是处理编译结果中的 Class 名称,需要适应上述的修改
UnoCSS

https://unocss.dev/config/variants

文档中有提到,Config 中的 Variants 可以完成对编译结果中 Class 名称的自定义 🧐

variants: [
  matcher => {
    return {
      matcher: matcher,
      selector: (s: any) => {
        if (/^(.+)?\[(.*)]$/.test(s)) {
          let res: any = s.replace(/\[/g, '_').replace(/\]/g, '_')
          s = res.replaceAll('\\', '')
        }
        if (s.includes(':')) {
          s = s.replace(':', '_')
        }
        if (s.includes("'")) {
          s = s.replaceAll("'", '-')
        }
        if (s.includes('"')) {
          s = s.replaceAll('"', '-')
        }
        if (s.includes('#')) {
          s = s.replaceAll('#', '-')
        }
        if (s.includes('/')) {
          s = s.replaceAll('/', '-')
        }
        if (s.includes('%')) {
          s = s.replaceAll('%', '-')
        }
        s = s.replaceAll('\\', '')
        return s
      },
    }
  },
],
  • 第一个判断作用于对 [] 的处理
  • 第二个判断作用于对 hover: active: ... 的处理
  • 第三以及第四对应 after:content-[''] after:content-[""] 的处理
  • ...
export default defineConfig({
  // ...UnoCSS options
  theme: {
    preflightRoot: ['page,::before,::after']
  },
  // ...variants
})

Vue

这里则是干涉 Vite 对 Vue 源码的编译,可以通过 Vite Plugin 实现

classHandlePlugin
export default function classHandlePlugin() {
  return {
    name: 'replace-class',
    transform(code: string, id: string) {
      if (id.endsWith('.vue')) {
        const pattern = /class="([^"]*)"/g
        code = code.replace(pattern, (_: any, className: string) => {
          let classItems = className.split(' ')
          classItems = classItems.map((item) => item.replace(/\n/g, ''))
          classItems = classItems.filter((item) => item !== '')
          classItems = classItems.map((item) => {
            if (/^(.+)?(\-\[(.*)])(.+)?$/.test(item)) {
              item = item.replace(/\[/g, '_').replace(/\]/g, '_')
              if (item.includes('\'')) {
                item = item.replaceAll('\'', '-')
              }
              if (item.includes('\"')) {
                item = item.replaceAll('\"', '-')
              }
              if (item.includes('#')) {
                item = item.replaceAll('#', '-')
              }
              if (item.includes('%')) {
                item = item.replaceAll('%', '-')
              }
            }
            if (item.includes('\/')) {
              item = item.replaceAll('\/', '-')
            }
            if (item.includes(':')) {
              item = item.replace(':', '_')
            }
            return item
          })
          className = classItems.join(' ')
          return class="${className}"
        })
      }
      return {
        code
      }
    }
  }
}
添加至 vite.config.ts
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import UnoCSS from 'unocss/vite'
import classHandlePlugin from './src/core/classHandlePlugin'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [classHandlePlugin(), uni(), UnoCSS()],
  resolve: {
    alias: {
      '@': '/src'
    }
  }
})

这里需要注意,classHandlePlugin() 需要放置在最前面 🤔

2️⃣ Example

3️⃣ End

当然,光引入完也是能用的,只是对于那些会产生不受小程序所支持的字符才需要进行上述处理 👀

抛开中括号 [] 可以采用类似 WindCSS 的写法

text-25px

.text-25px {
  font-size:25px;
}

不过对于某些情况,上述的处理并不能完全覆盖到,比如动态Class的处理 :class='[]' ,需要进一步完善正则

Comments | 2 条评论
  • 小起

    老哥,在hbuilderx中配置了,不报错了。编译后的class正常:m-[10rpx]变为了m-_10rpx_,但是css样式没有:m-_10rpx_{margin: 10rpx;} 这个没有出现

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息