图标数据来源

图标数据来源的方式有两种:

  • 从外部下载需要的图标数据到本地
  • 按照特定图标库的使用方式引入一系列图标,比如 Font Awesome

Iconify

一个图标框架,将流行的图标库集成在一起,通过一种方式方便地使用来自多个图标库的数据,支持通过 Vue 框架引入

在线图标

iconify 提供一个 vue 组件用于在线动态加载图标,即使用到的图标数据不会打包进构建产物中也能使用各种图标数据

安装依赖

pnpm add @iconify/vue

使用

<script setup lang="ts">
import { Icon } from '@iconify/vue'
</script>
 
<template>
	<Icon icon="mdi-light:home"></Icon>
</template>

mdi-light 表示使用的图标集,可选的图标集在这里查看

home 表示该图标集下的图标名称

现在可以在线动态加载图标了,但是仅限于可以使用外网的情况下

离线图标

如果项目只能在内网环境部署,那么 iconify 提供的 vue 组件就无法获取图标数据,虽然 iconify 也提供了离线图标的方式,但方式比较繁琐,因此有了 PurgeIcons 这个机制,这个机制会在构建后将图标数据嵌入到 DOM 中,不会发起任何请求,同时构建产物只包含使用到的图标数据,不会增加多余的打包体积

它提供了多种方式使用这个机制,下面用 vite 插件进行演示

安装依赖

pnpm add @iconify/iconify
pnpm add --save-dev vite-plugin-purge-icons @iconify/json 

其中 iconify/json 是可选的,代表所有图标数据,安装后,vite-plugin-purge-icons 会从本地读取图标数据,没有安装则尝试在线读取

配置

import PurgeIcons from 'vite-plugin-purge-icons'
 
export default {
  plugins: [
    PurgeIcons()
  ]
}

导入 @purge-icons/generatedmain.js

import { createApp } from 'vue'
import App from './App.vue'
 
import '@purge-icons/generated'
 
createApp(App).mount('#app')

使用方式

<span class="iconify" data-icon="fa:home"></span>

必须加上 class="iconify"

data-icon 属性值的形式和 @iconify/vue 一样

为了使用方便可以封装成一个组件 Icon.vue

<script setup lang="ts">
defineProps({
  icon: {
    type: String,
    required: true
  }
})
</script>
 
<template>
  <span class="iconify" :data-icon="icon"></span>
</template>

这样就达到了和 @iconify/vue 一样的引入图标方式

值得注意的是 PurgeIcons 文档里开头已经介绍到不再推荐这个使用图标的方式,而且仓库已经归档不再维护,不过我是为了兼容以前写法才继续选用这个方式

另外,如果你想实现动态切换图标,那就得绕给远路兼容一下,因为这个插件有个 bug 其没有被解决,猜测原因是基于 @iconify/iconfiy 的图标读取只在页面加载的运行时发生,但我们可以监听到图标变化后手动读取图标数据并插入到 DOM 中

<script setup lang="ts">
import { nextTick, ref, unref, watch } from 'vue'
 
const props = defineProps({
  icon: {
    type: String,
    required: true
  }
})
const elRef = ref<HTMLSpanElement | null>(null)
 
watch(
  () => props.icon,
  async () => {
    const span = document.createElement('span')
    span.className = 'iconify'
    span.dataset.icon = props.icon
    await nextTick()
    const el = unref(elRef)
    if (el) {
      el.textContent = ''
      el.appendChild(span)
    }
  },
  {
    immediate: true
  }
)
</script>
 
<template>
  <div ref="elRef" class="inline-block"></div>
</template>

VSCode 插件

安装这个插件后可以通过图标名称在 VSCode 中预览对应图标

疑难解答

@purge-icons/generated 没有安装,为什么可以使用?

虽然没有直接安装,但 vite-plugin-purge-icons 直接依赖了它,不过它是存在 node_modules/.pnpm 下,这里用于存储去重后的包,简单理解就多个依赖可能会共同依赖的包,node_modules 下的包都是通过软链指向该文件夹下的实际文件

理论上是可以直接引用的,但是不推荐这样做,会导致可读性降低,同时会存在构建工具无法解析的隐患,因此推荐直接安装一次 @purge-icons/geerated