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

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

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

准备svg文件

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

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

安装依赖

pnpm add -D unocss @iconify/utils glob

配置文件

vite.config.ts

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

uno.config.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`
});

使用图标

<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-: 固定前缀

menucustom: 文件夹名

exit-fullrefresh等: svg文件名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值