Vue3中优雅使用Icon

在 Vue3 中使用 Iconify 图标方案,可以利用其丰富的图标库和便捷的 SVG 图标集成方式来为你的应用添加矢量图标。以下是在 Vue3 项目中使用 Iconify 图标的详细步骤:

安装所需依赖

首先,确保你已经在项目中安装了 Vue3 以及 Vite(如果使用 Vite 作为构建工具)。然后,安装以下与 Iconify 相关的 npm 包:

1
pnpm add @iconify/vue

配置 Vite(仅适用于使用 Vite 插件的情况)

安装插件:unplugin-icons:按需加载所需图标库,unplugin-vue-components:自动引入组件,无需在单页面文件中 import

1
pnpm add unplugin-icons unplugin-vue-components -D

Unplugin-icons 支持三种方式引入 iconify 资源

  • 手动安装图标库

    直接安装整个 iconify 库,注意库大小比较大约 120M,结合 unplugin-icons 插件打包的时候并不会将所有的图标打包,只会打包使用到的图标

    1
    pnpm add @iconify/json
  • 手动安装图标集

    已经限定图标集的使用范围,安装特定的图标 sets,例如 Element-plus 图标库等。如果有用到其他库图标继续安装即可。

    1
    npm i -D @iconify-json/ep
  • 自动安装图标集

    自动安装图标集比较简单,无需引入图标库,只需要在 Icons 配置中加入 autoInstall 为 true。当使用 import 导入图标时会自动检测正确的包管理器并安装对应的图标集,如果搭配使用了 unplugin-vue-components 则不必 import 自动安装对应的图标 sets。

    1
    2
    3
    4
    5
    6
    7
    //vite.config.js
    plugins: [
    ...Icons({
    compiler: "vue3",
    autoInstall: true,
    }),
    ];

实例:引入并配置相关插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//vite.config.js
import { defineConfig } from "vite";
import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";
import Components from "unplugin-vue-components/vite";

export default defineConfig({
plugins: [
...Components({
resolvers: [
IconsResolver({
prefix: "icon", //自动引入的统一前缀,默认为i
}),
],
}),
Icons({
compiler: "vue3",
customCollections: {
// 如果有自定义图标集,可以在这里配置
},
defaultClass: "icon",
autoInstall: true,
}),
],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
// 如果使用全量导入模式,添加 Iconify 图标自动导入
"~icons": fileURLToPath(
new URL("./node_modules/@iconify/json", import.meta.url)
),
},
dedupe: ["@iconify/icons"],
},
optimizeDeps: {
include: ["@iconify/json"],
},
});

引入并使用 Iconify 图标

在 Vue 单文件组件(SFC)中,可以直接在模板中使用 <Icon> 组件来插入图标,这种情况需要考虑使用环境,因依赖 iconifyAPI 离线或内网环境下序要谨慎使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<div>
<!-- 使用 @iconify/vue 提供的 <Icon> 组件 -->
<Icon icon="mdi:home" />
</div>
</template>

<script>
import { Icon } from "@iconify/vue";

export default {
components: {
Icon,
},
};
</script>

如果您使用了并配置了 unplugin-icons unplugin-vue-components,您可以直接使用以下方式引入图标,而不需要做任何配置。这种使用方式并不会调用 iconifyAPI,您可以放心在离线或者内网环境下使用。

1
2
3
4
<template>
<IconAntDesignAccountBookFilled></IconAntDesignAccountBookFilled>
<IconAntDesignAndroidFilled></IconAntDesignAndroidFilled>
</template>

离线环境或者内网环境下使用 iconify 图标

如您使用步骤三且并没有明确将使用哪个图标的情况下,默认会走 iconify API 的模式去导入相关的 icon sets。若恰巧此时您并不知道程序给您做了哪些操作,在离线或者内网环境下可能会造成请求失败,图标不显示的问题。如果您遇到这个问题,您应该首先注意并定位到 API 调用出错,解决办法:

1
2
3
4
5
6
7
8
9
// 在此之前您需要明确您使用了哪些sets的图标并安装对应的sets图标集
import { addCollection } from "iconify-icon";
import uimIcons from "@iconify/json/json/uim.json";
import lineMdIcons from "@iconify/json/json/line-md.json";
import wiIcons from "@iconify/json/json/wi.json";
// 注册图标
addCollection(uimIcons);
addCollection(lineMdIcons);
addCollection(wiIcons);

如果您在 vue 中使用您可以尝试将抽离出一个安装 iconify 特定 sets 的方法并在 main.js 调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { addCollection } from '@iconify/vue'
import uimIcons from '@iconify/json/json/uim.json'
import lineMdIcons from '@iconify/json/json/line-md.json'
import wiIcons from '@iconify/json/json/wi.json'

export async function iconifyInstall {
addCollection(uimIcons)
addCollection(lineMdIcons)
addCollection(wiIcons)
}

// main.js
import { iconifyInstall } from './iconify/index'
iconifyInstall()

配置图标样式

根据需要,可以在全局或局部样式文件中调整图标的颜色、大小等属性。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* 全局样式表 */
.iconify-icon,
.custom-icon {
fill: currentColor;
width: 1em;
height: 1em;
vertical-align: middle;
}

/* 或者在单个组件内 */
<style scoped>
.custom-icon {
font-size: 24px;
color: #3f51b5;
}
</style>

封装 iconify 组件

简单封装一下 iconify 组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<iconify-icon
:icon="icon"
:rotate="`${rotate}deg`"
:width="width"
:style="{
color: color,
}"
></iconify-icon>
</template>

<script setup lang="ts">
defineProps({
icon: {
type: String,
required: true,
},
color: {
type: String,
default: "#999999",
required: false,
},
width: {
type: [String, Number],
default: "20",
required: false,
},
rotate: {
type: [String, Number],
default: "0",
required: false,
},
});
</script>