前言
离线图标引入方式有多种, 可通过单图标 图标集合 离线api服务器方式来部署
通过新建项目来验证是否满足离线要求/打包后大小
vue项目创建
使用vite创建vue项目, 核心依赖unocss/@iconify/json/@iconify/vue
"dependencies": {
"vue": "^3.4.29"
},
"devDependencies": {
"@vitejs/plugin-vue-jsx": "^4.0.1",
"unocss": "^0.64.0",
"@iconify/vue": "^4.1.2",
"@iconify/json": "^2.2.268",
"@vitejs/plugin-vue": "^5.0.5",
"typescript": "^5.2.2",
"vite": "^5.3.1",
"vue-tsc": "^2.0.21"
}
uno.config.ts
import { defineConfig, presetUno, presetIcons } from 'unocss';
export default defineConfig({
presets: [presetUno(), presetIcons()],
});
核心presetIcons, 详见官网: unocss.dev/presets/ico… tailwindcss同理
这里提到If you prefer to install all the icon sets available on Iconify at once (~130MB):
使用iconify/json包会将图标打包 是否真的是这样呢 来测试一下
// test.tsx
import { defineComponent } from 'vue';
export default defineComponent({
name: 'Test',
setup() {
return () => <div class="i-file-icons:config-typescript w-1em h-1em"></div>;
},
});
<template>
<div class="flex justify-center items-center">
<div class="i-hugeicons:electric-home-02 w-3em h-3em"></div>
<Test />
</div>
</template>
<script setup lang="ts">
import Test from './test';
</script>
图标都是随便在iconify找的
可以正常加载图标
打包看看 是否会在线请求还是离线图标
可以看到没有网络请求
两个图标都打包进了css
但是这种方式只适合固定的静态的图标 如果动态加载会怎样呢?
动态图标
将图标放在服务器返回 可以看到已经无法渲染了
<template>
<div class="flex justify-center items-center">
<div v-for="icon in icons" class="w-3em h-3em" :class="icon"></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
function wait(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const icons = ref<string[]>([]);
onMounted(async () => {
await wait(1000);
await fetch('http://localhost:8080/test').then(async (response) => {
const iconList = await response.json();
icons.value = iconList;
});
});
</script>
使用全部图标集
上面使用了三个图标集, 直接添加全部图标集
import { createApp } from 'vue';
import App from './App.vue';
import 'uno.css';
import { addCollection } from '@iconify/vue';
import mdi from '@iconify/json/json/mdi.json';
import vscode from '@iconify/json/json/vscode-icons.json';
import hugeicons from '@iconify/json/json/hugeicons.json';
addCollection(mdi);
addCollection(vscode);
addCollection(hugeicons);
createApp(App).mount('#app');
<template>
<div class="flex justify-center items-center">
<div v-for="icon in icons" class="w-3em h-3em">
<Icon :icon="icon" />
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Icon } from '@iconify/vue';
function wait(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const icons = ref<string[]>([]);
onMounted(async () => {
await wait(1000);
await fetch('http://localhost:8080/test').then(async (response) => {
const iconList = await response.json();
icons.value = iconList;
});
});
</script>
可以正常加载, 没有网络请求
但是!! 打包看看
添加图标集后
可以看到图标集里的图片全部被打包进js了
添加图标集前
80K 加了三个图标飙升至9M大小 这种全量级别的添加肯定是不合适
使用单个图标
上面使用了三个图标集, 单个引入的话不能从iconify/json中引入, 需要下载对应的@iconify/icons-图标集npm包
pnpm i @iconify/icons-mdi -D
pnpm i @iconify/icons-vscode-icons -D
// 剩下一个没有npm包 也是第一次见 绝大部分都是有的
mian.ts
import { createApp } from 'vue';
import App from './App.vue';
import 'uno.css';
import { addIcon } from '@iconify/vue';
import icon1 from '@iconify/icons-mdi/language-typescript';
import icon2 from '@iconify/icons-vscode-icons/file-type-typescript';
addIcon('mdi:language-typescript', icon1);
addIcon('vscode-icons:file-type-typescript-official', icon2);
createApp(App).mount('#app');
这里需要注意图标名称必须对应, 我这里是后台返回图标两者必须相等
可以看到没添加离线图标的走的还是在线 剩下的都是离线
看看打包大小
只多了2K左右的大小 图标打包进js
总结
使用unocss/tailwindcss+@iconify/json 图标会被打包进css 不适合动态(后端返回)图标
<div class="i-file-icons:config-typescript w-1em h-1em"></div>
使用图标集/单个图标 图标会打包进js 可动态(后端返回)图标
<template>
<Icon icon="xxx" />
</template>
<script>
import { Icon } from '@iconify/vue';
</script>
Icon在能找到本地图标(name对应)或图标集情况使用本地(离线)图标 否则会使用线上(cdn)图标
自动引入图标
安装依赖
pnpm i -D unplugin-icons
vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Unocss from 'unocss/vite';
import useJsx from '@vitejs/plugin-vue-jsx';
import Icons from 'unplugin-icons/vite';
export default defineConfig({
plugins: [vue(), Unocss(), useJsx(), Icons({ compiler: 'vue3' })],
});
如果使用了ts, 需要添加类型 任选其一 <https://github.com/unplugin/unplugin-icons/issues/235>
1. tsconfig.json
"types": ["unplugin-icons/types/vue"]
2. .d.ts
/// <reference types="unplugin-icons/types/vue" />
vue文件
<template>
<div class="flex justify-center items-center">
<IconParkFileStaff />
</div>
</template>
<script setup lang="ts">
import IconParkFileStaff from '~icons/icon-park/file-staff';
</script>
可以在这里找到导入
打包大小:
正常离线