图标
简要介绍
图标是文字的隐喻,可以实现视觉引导和功能划分。
IconFont
Teek 内置 IconFont 阿里巴巴矢量图标库 组件,这是国内功能很强大且图标内容很丰富的矢量图标库,提供矢量图标下载、在线存储、格式转换等功能。
SVG
Teek 内置 SVG 组件,SVG 是使用 XML 来描述二维图形和绘图程序的语言。
Iconify
Teek 内置 Iconify 图标库组件,Iconify 是一个开源、统一的矢量图标库,市面上流行的图标都被收集到该库里,基本满足 99%
的使用场景。
官方链接:
在 Teek 里,Iconify 的图标支持在线模式和本地模式。
图标组件使用
Teek 封装的 icon
组件已经全局注入到 Teek 里,全局注入的位置在 src/main.ts
里。
封装的 Icon 组件为了兼容各个图标类型,使用时需要告诉 Icon 组件使用哪个类型,有 2 种方式:
- 传入
iconType
属性:
Icon 组件默认支持如下类型的图标:
export type CommonIconType =
| "svg"
| "unicode"
| "iconfont"
| "symbol"
| "img"
| "component"
| "iconifyOffline"
| "iconifyOnline";
使用:
<script setup lang="ts"></script>
<template>
<Icon icon="icon-dagouyouquan" icon-type="iconfont" />
</template>
- 传入特定的前缀:
- icon 为 img- 或 IMG- 开头,则默认为 img
- icon 为 if- 或 IF- 开头,则默认为 iconfont
- icon 为 uni- 或 UNI- 开头,则默认为 unicode
- icon 为 sym- 或 SYM- 开头,则默认为 symbol
- icon 为 svg- 或 SVG- 开头,则默认为 svg
<script setup lang="ts"></script>
<template>
<Icon icon="IF-icon-dagouyouquan" />
</template>
提示
Icon
组件会自动识别传入的 icon
属性是否是一个组件或以图片格式结尾,因此这两类无需传入 iconType
或者添加前缀。
IconFont
Teek 默认已经全局引入了大量常用的 IconFont
图标,如果这些图标仍然无法满足需求,可以去 阿里巴巴矢量图标库 进行收集和下载,下载后建议将其解压到 src/common/assets/iconfont
下。
当然你也可以解压到项目的任意位置,只需要在使用 IconFont 的时候引用下载的 js、css 文件。
如何使用?
假设下载的文件里有一个图标名:icon-dagouyouquan
。
在组件里这样使用:
<script setup lang="ts">
import "@/assets/iconfont/iconfont.js";
import "@/assets/iconfont/iconfont.css";
</script>
<template>
<Icon icon="icon-dagouyouquan" icon-type="iconfont" />
<!-- 或者 -->
<Icon icon="IF-icon-dagouyouquan" />
</template>
如果你觉得使用 IconFont 时候都需要引用文件:
import "@/assets/iconfont/iconfont.js";
import "@/assets/iconfont/iconfont.css";
那么可以将这两段代码放到 src/main.ts
文件里来进行全局注册,这样就不需要再额外引入这两个文件。
SVG
SVG 图标都以 .svg
结尾,并且 SVG 图标存放的目录必须是一个固定的目录:src/common/assets/icons
下,因为 Teek 需要将所以的本地 SVG 图标进行扫描并注册,因此扫描的目录必须是一个固定的目录,如果你想修改 SVG 存放的目录,则去 node/plugin.ts
文件里修改:
// 使用 svg 图标
createSvgIconsPlugin({
iconDirs: [resolve(process.cwd(), "src/common/assets/icons")],
symbolId: "icon-[dir]-[name]",
}),
src/common/assets/icons
就是需要修改 SVG 存放的位置。
如何使用?
SVG 的使用方式非常简单,假设:
src/common/assets/icons
下有一个apply.svg
图标名src/common/assets/icons/core
下有一个core.svg
图标名
<script setup lang="ts"></script>
<template>
<!-- 在 icons 目录下找 apply.svg -->
<Icon icon="apply"></Icon>
<!-- 在 icons/core 目录下找 bug.svg -->
<Icon icon="core-bug"></Icon>
</template>
提示
Icon
组件如果不传入前缀或者 iconType
,则默认是 SVG 图标
Iconify
在线图标
如果您的项目部署在互联网上,那么可以使用 Iconify 的在线图标,只需要往 Icon
组件传入在线图标名称即可。
如想引用 Element Plus 的 Add Location
,就可以这些写:
<script setup lang="ts"></script>
<template>
<Icon icon="ep:add-location"></Icon>
</template>
其中 ep:add-location
为在线图标名,更多的在线图标请访问:
然后随便点开一个图标库,接着随便点击一个图标,往下看我们就可以看到该图标的在线名字,在线名字一般都是 图标库名 + :
+ 图标名 作为在线图标名。
如果项目部署在内网,或担心网络访问速度慢导致无法加载图标怎么办?往下看。
离线 JSON 图标
您可以直接将 Iconify
图标以 JSON 方式注册到本地,然后引入到 TkIcon
组件里,如:
pnpm add @iconify-json/ant-design -d
然后在 .vitepress/theme/index.ts
里注册到 Teek 里:
import { addIcons } from "@/components/core/icon";
import icons from "@iconify-json/ant-design/icons.json";
addIcons(icons);
最后和在线方式一样使用 Icon
组件:
<Icon icon="ant-design:account-book-filled" />
Icon
优先从已注册的图标名里获取,当获取不到时就会从互联网上下载。
这里演示安装了 ant design
的图标,其他的图标集合根据需要安装。
Iconify
JSON 图标的依赖名约定是 @iconify-json/{name}
,引入 JSON 图标数据的路径约定是 @iconify-json/{name}/icons.json
。
离线 Icon 图标
您可以直接将 Iconify
的图标集合安装到本地,然后引入到 TkIcon
组件里,如:
pnpm add @iconify-icons/ant-design -d
然后使用:
<script setup>
import Upload from "@iconify-icons/ant-design/upload";
</script>
<Icon :icon="Upload" />
这里演示安装了 ant design
的图标,其他的图标集合根据需要安装。
Iconify
Icon 图标的依赖名约定是 @iconify-icons/{name}
或者 @iconify/icons-{name}
,如:
# pnpm
pnpm add @iconify/icons-ant-design
# 或
pnpm add @iconify-icons/ant-design
两个离线图标方式对比
- JSON 图标方式需要在项目初始化时注册进去,后续直接通过字符串引用
- Icon 图标方式在每次使用时需要手动引入
信息
Icon
并没有实现 Iconify
相关逻辑,而是通过代理 Iconify
的 API 实现。
组件图标
Teek 也支持传入组件图标,如 ElementPlus 的图标:
<script setup>
import { Odometer } from "@element-plus/icons-vue";
</script>
<template>
<Icon :icon="Odometer" />
<!-- 或者 -->
<Icon>
<Odometer />
</Icon>
</template>
组件图标不需要传入前缀或者 iconType
,内部会自动识别。
图片
如果传入的 icon
带有 .png
、.jpg
、.jpeg
、.gif
、.bmp
、webp
后缀,则 Teek 会将图标渲染为图片(使用 img
标签)。
<Icon icon="https://xxx/logo.png" />
全局注册图标
如果 Teek 要使用高频的图标,我们需要经常 import from
会显得很麻烦,那么我们可以在 Teek 加载的时候,往 Teek 注入一些高频使用的图标,然后引用的时候,直接填写图标名,不需要引入。
Element Plus
如果是 ElementPlus 图标,需要在 src/main.ts
里使用 app 来全局注册。
全部引入:
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component);
}
key 是图标的名字。
按需引入:
import { Edit } from "@element-plus/icons-vue";
app.component("edit", Edit);
使用:
<Icon icon="edit"></Icon>
Iconify
如果是 Iconify 图标,可以使用 addIcon
函数来加载图标,该函数将将图标全局注册到 Teek 里。
在 src/layout/index.vue
里添加如下:
import { addIcon } from "@iconify/vue";
import Edit from "@iconify-icons/ep/edit";
addIcon("edit", Edit);
addIcon
的第一个参数就是该图标的名字,使用的时候引用该名字就可以了:
<Icon icon="edit"></Icon>
如果 addIcon
比较多,可以单独放到一个文件里,如将代码放到 src/layout/offlineIcon.ts
下,然后在 src/layout/index.vue
引入:
import "@/layout/offlineIcon";
Icon 组件 Props 类型
Icon 组件可以传入的 props 类型:
import type { Component } from "vue";
import type { IconifyIcon } from "@iconify/vue";
export type CommonIconType =
| "svg"
| "unicode"
| "iconfont"
| "symbol"
| "img"
| "component"
| "iconifyOffline"
| "iconifyOnline";
export type CommonIcon = string | Object | Component | IconifyIcon;
export interface IconProps {
/**
* 图标
*/
icon?: CommonIcon;
/**
* 图标类型
*/
iconType?: CommonIconType;
/**
* 图标大小
*
* @default 'inherit'
*/
size?: string | number;
/**
* 图标颜色
*
* @default 'inherit'
*/
color?: string;
/**
* 图标是否可悬停
*
* @default false
*/
hover?: boolean;
/**
* 图标悬停时的颜色,仅当 hover 为 true 时有效
*/
hoverColor?: string;
/**
* img 标签的 alt,当 iconType 为 img 时生效
*/
imgAlt?: string;
/**
* 是否使用鼠标手形
*/
pointer?: boolean;
/**
* 自定义图标样式
*/
style?: Record<string, any>;
}
使用例子:
<Icon icon="IF-icon-dagouyouquan" :size="200" />
Icon 组件原理
Teek 封装了 Icon 组件来满足不同的使用场景,那么原理是什么呢?
封装 Icon 的相关文件都在 src/components/core/icon
下。
我们可以点进去看 Icon 组件源码,可以看到 Icon 组件的引用:
import SvgIcon from "./components/svg-icon.vue";
import FontIcon from "./components/font-icon.vue";
import IconifyOnline from "./components/iconify-online.vue";
import IconifyOffline from "./components/iconify-offline.vue";
于是我们可以知道,Icon 组件就类似于一个集成入口,它内置了:
- SVG 组件:
SvgIcon
- IconFont 组件:
FontIcon
- 在线 Iconify 组件:
IconifyOnline
- 本地 Iconify 组件:
IconifyOffline
Icon 通过传入的 IconType
属性或者 icon
前缀规则来判断属于哪一类图标,从而渲染对应的组件。
当然你也可以直接对应的图标组件:
<script setup lang="ts">
import { FontIcon } from "@/components/core/icon";
import "@/assets/iconfont/iconfont.js";
import "@/assets/iconfont/iconfont.css";
</script>
<template>
<FontIcon icon="icon-dagouyouquan"></FontIcon>
</template>
<script setup lang="ts">
import { SvgIcon } from "@/components/core/icon";
</script>
<template>
<SvgIcon icon="bug"></SvgIcon>
</template>
<script setup lang="ts">
import { IconifyOnline } from "@/components/core/icon";
</script>
<template>
<IconifyOnline icon="ep:add-location"></IconifyOnline>
</template>
<script setup lang="ts">
import { IconifyOffline } from "@/components/core/icon";
import Upload from "@iconify-icons/ant-design/upload";
</script>
<template>
<IconifyOffline icon="Upload"></IconifyOffline>
</template>
VSCode 图标插件
使用 Iconify 并且开发 IDE 是 VSCode,那么可以安装 antfu.iconify
插件,该插件可以在引用 Iconify 的图标时,直接在代码里显示该图标。