Whidy Writes

UnoCSS动态图标icon无法显示解决方案

发布于:(更新于:

这几天遇到了一个奇怪的问题,使用UnoCSS过程中,有的icon图标能够正常显示,但是有的不能,当然最糟糕的事,我找了几天,才发现诡异之处。

问题描述

首先UnoCSS是无法通过动态的方式解析到你可能用到的icon,主要是以下2个场景可能会无法显示icon图标:

  • 后台管理系统的菜单,由后端返回菜单数据信息包含icon类名或在路由文件的meta信息中包含,由模板遍历数据来显示(我就是在这个场景下出现问题的)
  • 自己封装icon组件、通过props传递icon图标信息进行拼接的

很显然,稍微了解UnoCSS引擎的朋友,大概可以推测到,动态加载进去的图标类名无法被检测到,所以也就不能显示了,如何解决这个问题呢。

解决方案

【2023年08月15日】更新

在完成 UnoCSS v0.55.0 的一个入门教程UnoCSS-Study-Examples的时候,我仔细阅读官方文档,发现有一个新的配置项可以完美解决这个问题。这里称之为终极解决方案。

而文中的需求你可能还是要看下,这里直接说方案。

完美方案:调整UnoCSS配置文件

将需要被扫描的文件添加到配置中,比如我项目中的路由文件路径 src/router/index.ts ,那么在 uno.config.ts 中添加一段:

export default defineConfig({ // ... content: { pipeline: { include: [ // the default /\.(vue|svelte|[jt]sx|mdx?|astro|elm|php|phtml|html)($|\?)/, // 这里只写我需要的,当然你也可以定制,参考:https://unocss.dev/guide/extracting#extracting-from-build-tools-pipeline "src/router/index.ts", ], // exclude files // exclude: [] } } )}

这样就免去了之前写 // @unocss-include 的麻烦,也更好管理。

与此同时,官方还出了异步方式来提前解析可能存在的各种特殊情况,这里我就不赘述了,可以看完整的说明:动态加载icon。那么这个动态加载无论是icon还是一些特殊的class名,都能较好的处理了~


因为我是在做菜单组件时候发现的问题,所以以菜单的场景举例说明。

方案一:图标预加载

在菜单组件写一段“没有用”的代码

<div v-if="false" i-mdi-poll i-mdi-monitor-dashboard i-mdi-ballot-recount-outline i-mdi-application-brackets-outline i-mdi-apache-kafka i-mdi-archive-search-outline i-mdi-format-text-wrapping-overflow></div>

当然你不想用 v-if 换成 hidden 也是可以的。同样的你想统一管理这所有的动态加载的icon,也可以专门写到 index.html 进行补充,因为默认状态下这些都能被UnoCSS识别到。

方案二:项目文件添加到UnoCSS扫描范围【推荐】

其实这个方案就很不错了,比如我是Vue的菜单组件中调用路由( router/menu.ts )内的每条路由记录的meta中icon,那么就给这个 menu.ts 文件顶部加一段注释

// @unocss-include export const menuRoutes = [{ name: "Index", path: "/", component: () => import("@/layout/index.vue"), isHidden: true, redirect: "/dashboard/overview", meta: { title: "首页", }, children: [{ name: "Dashboard", path: "/dashboard", component: () => import("@/views/dashboard/index.vue"), redirect: "/dashboard/overview", meta: { title: "看板", icon: "i-mdi-poll", }, // ... }] }]

这样就解决了。相同的原理,如果你想统一管理,也可以创建一个单独的文件在src目录下,比如叫做 unocss-icon.ts ,然后再在 main.ts 内引入就好了。这完全取决于你的喜好~

// unocss-icon.ts // @unocss-include const iconList = ["i-mdi-poll", "i-mdi-monitor-dashboard", "i-mdi-ballot-recount-outline", "i-mdi-application-brackets-outline", "i-mdi-apache-kafka", "i-mdi-archive-search-outline", "i-mdi-format-text-wrapping-overflow" ];
// main.js // 添加一行 import "./unocss-icon";

后记

我在Github上也做了一个简单的模板,大家可以参考一下:Vite-Element-Plus-UnoCSS

另外,为啥看起来挺简单的问题,我搞了几天。原因有几点:

  • 才上手 UnoCSS 不到一周,虽然主要功能了解,但细节仍有许多不清楚。
  • 我做菜单时,最早写的纯静态Vue组件,用的 el-menu ,没有结合路由,并且只给一级菜单加了图标,后来改造的时候,把旧的代码注释掉了,但没删除,然后通过 menu.ts 动态获取,这时,因为旧的Vue组件没有删,所以旧的图标还在,但是我给二级菜单添加的图标是之前没有的,所以造成了有的图标有,有的没有,就是旧代码注释未删除造成的假象。这也算把自己坑了~

而上面提到的解决方案之前是没有搜出来的,也没想到是因为不支持动态加载图标造成的,当我后来反复摸索发现了这个问题,才去 issue 寻找是否有人遇到类似的情况,发现确实有。

antfu 也做了一些解释,相关的issues我整理如下:

最后,最佳解决方案也是参考:UnoCSS - Scanning

avatar

whidy

一名爱折腾的前端开发工程师,喜欢打篮球和分享 ฅʕ•̫͡•ʔฅ