网络图标组件:动态加载 Iconfont CSS 文件
Iconfont CSS 引用方式
Iconfont 平台支持多种引用方式,其中 Symbol 引用在上一节已介绍(通过 vite-plugin-svg-icons)。本节介绍 Font Class 引用方式,通过动态加载 CSS 文件实现远程图标渲染。
常规方式:HTML 静态引入
<!-- index.html -->
<head>
<link
rel="stylesheet"
href="//at.alicdn.com/t/c/font_xxxxx_xxxxx.css"
/>
</head>
html
然后在模板中使用:
<template>
<i class="iconfont icon-kefu"></i>
</template>
vue
这种方式简单直接,但存在不足:需要在 index.html 中硬编码 link 标签,URL 更新时需手动修改 HTML 文件。
动态加载组件:NetIcon
通过组件方式动态加载 Iconfont CSS,实现更灵活的管理。
类型定义
// src/components/types.d.ts
export interface NetIconProps {
/** Iconfont CSS 文件地址(远程或本地) */
url?: string
/** 图标 class 前缀,对应 Iconfont 项目设置中的 Font Class 前缀 */
prefix?: string
/** Font Family 名称 */
fontFamily?: string
/** 图标名称 */
type: string
}
typescript
NetIcon 组件实现
<!-- src/components/NetIcon/NetIcon.vue -->
<script setup lang="ts">
import { computed, onBeforeMount } from 'vue'
import type { NetIconProps } from '../types'
const props = withDefaults(defineProps<NetIconProps>(), {
url: '',
prefix: 'iconfont',
fontFamily: 'iconfont',
})
// 拼接完整的 class 名
// 结果形如: "iconfont icon-kefu"
const className = computed(() => {
return `${props.fontFamily} ${props.prefix}-${props.type}`
})
// 动态加载 CSS 文件
onBeforeMount(() => {
if (!props.url) return
// 检查是否已存在相同 URL 的 link 标签,避免重复加载
const existingLink = document.querySelector(
`link[href="${props.url}"]`
)
if (existingLink) return
const link = document.createElement('link')
link.href = props.url
link.rel = 'stylesheet'
document.head.appendChild(link)
})
</script>
<template>
<i :class="className" />
</template>
vue
核心逻辑说明:
- 防重复加载:通过
querySelector检查同一 URL 的 link 标签是否已存在 - 浏览器缓存:相同 URL 的 CSS 只请求一次,后续由浏览器缓存处理
- 生命周期:在
onBeforeMount中加载 CSS,确保渲染时样式已就绪 - computed class:动态拼接
fontFamily + prefix-type的 class 名
业务封装:IconfontIcon
将固定的 URL 封装到业务组件中,简化使用:
<!-- src/components/IconfontIcon/IconfontIcon.vue -->
<script setup lang="ts">
import NetIcon from '../NetIcon/NetIcon.vue'
import type { NetIconProps } from '../types'
const props = withDefaults(defineProps<NetIconProps>(), {
// 远程 CDN 地址
url: '//at.alicdn.com/t/c/font_xxxxx_xxxxx.css',
prefix: 'iconfont',
fontFamily: 'iconfont',
})
</script>
<template>
<!-- v-bind="$attrs" 透传所有属性(如 class、style、事件等) -->
<NetIcon
:url="props.url"
:prefix="props.prefix"
:font-family="props.fontFamily"
:type="props.type"
v-bind="$attrs"
/>
</template>
vue
使用方式
<!-- src/pages/index.vue -->
<script setup lang="ts">
import IconfontIcon from '@/components/IconfontIcon/IconfontIcon.vue'
</script>
<template>
<!-- 远程加载 -->
<IconfontIcon type="kefu" class="text-2xl text-blue-500" />
<IconfontIcon type="yicain" class="text-xl text-red-500" />
<!-- TypeScript 类型校验生效 -->
<!-- <IconfontIcon :type="123" /> --> <!-- TS 报错: type 应为 string -->
</template>
vue
本地化部署
将 Iconfont CSS 下载到本地 public 目录,实现完全离线使用。
步骤
- 从浏览器 Network 面板下载 CSS 文件
- 放到
public/fonts/iconfont.css - CSS 中引用的字体文件也需放到对应路径
public/
└── fonts/
├── iconfont.css
├── iconfont.woff2
├── iconfont.woff
└── iconfont.ttf
bash
- 修改 CSS 中的字体文件路径为相对路径
/* public/fonts/iconfont.css */
@font-face {
font-family: "iconfont";
src: url('./iconfont.woff2') format('woff2'),
url('./iconfont.woff') format('woff'),
url('./iconfont.ttf') format('truetype');
}
css
- 修改业务组件的 URL 指向本地路径
<!-- src/components/IconfontIcon/IconfontIcon.vue -->
<script setup lang="ts">
import NetIcon from '../NetIcon/NetIcon.vue'
import type { NetIconProps } from '../types'
const props = withDefaults(defineProps<NetIconProps>(), {
// 改为本地路径
url: '/fonts/iconfont.css',
prefix: 'iconfont',
fontFamily: 'iconfont',
})
</script>
<template>
<NetIcon
:url="props.url"
:prefix="props.prefix"
:font-family="props.fontFamily"
:type="props.type"
v-bind="$attrs"
/>
</template>
vue
图标加载方式对比
| 方案 | 加载方式 | 颜色可控 | 离线可用 | 类型安全 | 适用场景 |
|---|---|---|---|---|---|
<link> 静态引入 | HTML 头部 | 是(通过 color) | 否 | 否 | 简单项目快速集成 |
| NetIcon 组件 | 动态 JS | 是(通过 color) | 支持本地路径 | 是(TypeScript) | 需要灵活管理多个图标集 |
| IconfontIcon 封装 | 动态 JS | 是 | 支持本地路径 | 是 | 单一项目图标集 |
| SVG Symbol 引用 | 构建时 | 是 | 是 | 是 | 自定义 SVG 图标 |
TypeScript Props 校验
通过 types.d.ts 定义接口,defineProps 结合 withDefaults 实现完整的类型推导:
// src/components/types.d.ts
export interface NetIconProps {
url?: string
prefix?: string
fontFamily?: string
type: string // 必填
}
typescript
// 组件中使用
const props = withDefaults(defineProps<NetIconProps>(), {
url: '',
prefix: 'iconfont',
fontFamily: 'iconfont',
})
// props.type 必填,TypeScript 编译时校验
typescript
这种写法相比 Options API 的 defineProps 方式更简洁,同时保持完整的类型推导和默认值支持。
注意事项
- Iconfont 项目设置中的 Font Class 前缀决定
prefix的默认值,需与 Iconfont 后台配置一致 - CSS 文件更新后,URL 中的哈希值会变化,需同步更新组件中的 URL
- SSR 场景下
document不可用,需加客户端判断:if (import.meta.client)(Nuxt)或if (typeof document !== 'undefined') - 多图标集场景可创建多个业务组件,分别指向不同的 Iconfont 项目 URL
↑