Vue3+TS中svg图标的使用-@unocss/preset-icons

@unocss/preset-icons 是 UnoCSS 提供的图标预设,支持从 本地和在线图标库 加载图标,本文介绍本地图标库的使用

从 blog.csdn.net/u013737132/... 得知vite-plugin-svg-icons 插件停止维护,依赖过时,便整理替代品

准备svg文件

src/assets/icons下随意创建文件夹custom,menu

从网络上下载svg文件复制到两个文件夹下

安装依赖

bash 复制代码
pnpm add -D unocss @iconify/utils glob

配置文件

vite.config.ts

ts 复制代码
...
import vue from '@vitejs/plugin-vue'
// 导入Unocss插件
import Unocss from 'unocss/vite'
...
export default defineConfig({
	plugins: [
        vue(),
        // 注册Unocss插件
        Unocss(),
    ]
})

uno.config.ts

ts 复制代码
import { defineConfig, presetIcons, presetWind3 } from "unocss";
import { FileSystemIconLoader } from "@iconify/utils/lib/loader/node-loaders";
import { globSync } from 'glob'
import path from 'node:path'

/**
 * 获取 src/assets/icons/ 目录下的所有 svg图标文件
 * 实际只适用 icons的下一级目录,再下级目录不支持
 */
const iconsDirPattern = "./src/assets/icons/**/*.svg";
const files = globSync(iconsDirPattern, { nodir: true }) // nodir:true 不匹配目录,只匹配文件
// 读取本地 SVG 目录,获取所有 svg 图标,并按照文件夹分类
/**
 * 返回数据格式
 * {
 *   menu: [ 'i-menu:home' ],
 *   custom: [
 *     'i-custom:welcome',
 *     'i-custom:refresh',
 *     'i-custom:phone',
 *     'i-custom:logout',
 *     'i-custom:lock',
 *     'i-custom:loading',
 *     'i-custom:juejin',
 *     'i-custom:home',
 *     'i-custom:full-screen',
 *     'i-custom:exit-full',
 *     'i-custom:copyright'
 *   ]
 * }
 */
function getIcons() {
  const icons = {}
  files.forEach((filePath) => {
    const fileName = path.basename(filePath) // 获取文件名,包括后缀
    const fileNameWithoutExt = path.parse(fileName).name // 获取去除后缀的文件名
    const folderName = path.basename(path.dirname(filePath)) // 获取文件夹名
    if (!icons[folderName]) {
      icons[folderName] = []
    }
    icons[folderName].push(`i-${folderName}:${fileNameWithoutExt}`)
  })
  return icons
}
const icons = getIcons()
/**
 * 读取本地 SVG 目录,获取所有 svg 图标,并按照文件夹分类
 * 返回数据格式
 * collections {
 *   menu: [AsyncFunction (anonymous)],
 *   custom: [AsyncFunction (anonymous)]
 * }
  */
const collections = Object.fromEntries(Object.keys(icons).map(item => [
  item,
  FileSystemIconLoader(`src/assets/icons/${item}`, (svg) => {
    return svg.includes('fill="')
      ? svg
      : svg.replace(/^<svg /, '<svg fill="currentColor" ');
  })
]))

/**
 * 使用安全列表,在UnoCSS中使用动态生成的className名称
 * 提前声明那些动态生成的类名,以确保它们在最终的CSS中被包含
 * 返回数据格式
 * [
 *   'i-menu:home',
 *   'i-custom:welcome',
 *   'i-custom:refresh',
 *   'i-custom:phone',
 *   'i-custom:logout',
 *   'i-custom:lock',
 *   'i-custom:loading',
 *   'i-custom:juejin',
 *   'i-custom:home',
 *   'i-custom:full-screen',
 *   'i-custom:exit-full',
 *   'i-custom:copyright'
 * ]
 */
const generateSafeList = () => {
  return Object.keys(icons).flatMap((item) => icons[item])
};

export default defineConfig({
  presets: [
    // https://unocss.dev/presets/wind3
    presetWind3(),
    // 预设图标
    presetIcons({
      warn: true,
      prefix: ['i-'],
      // 设置全局图标默认属性
      extraProperties: {
        width: "1em",
        height: "1em",
        display: "inline-block",
      },
      // 注册本地 svg 图标集合
      collections,
    }),
  ],
  safelist: generateSafeList(), // 动态生成 `safelist`
});

使用图标

html 复制代码
<template>
  <div class="home">
    <h2>home</h2>
    测试preset-icons
    <i class="i-custom:exit-full text-#0033cc text-2xl" />
    <i class="i-menu:refresh" />
    <i class="i-custom:juejin text-red text-[50px]" />
    <i class="i-custom:lock hover:text-sky " />
  </div>
</template>

<script setup lang="ts">
</script>

<style scoped>

</style>

i-: 固定前缀
menu或custom: 文件夹名
exit-full或refresh等: svg文件名

相关推荐
卸任19 小时前
Vibe coding工具使用心得
前端·ai编程
brien919 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance20 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M20 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写20 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李20 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易20 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马20 小时前
前沿视界
前端
kyriewen20 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易21 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员