一次完整的 iconfont 字体图标调试之旅
前言
在 HarmonyOS 应用开发中,使用 iconfont 字体图标是一种常见的 UI 实现方式。然而在实际开发中,经常会遇到"字体文件已加载但图标不显示"的问题。本文记录了一次完整的 iconfont 调试过程,总结了常见问题及解决方案。
问题现象
应用中使用了自定义的 iconfont.ttf 字体文件,但在页面渲染时,所有图标位置都显示为空白方框 ⬜,即使日志显示字体已成功注册。
typescript
// 日志显示注册成功
[Font] iconfont registered successfully
// 但页面显示空白方框
Text('\ue81a')
.fontFamily('iconfont') // 显示 ⬜ 而不是图标
问题排查过程
第一步:检查字体文件路径
问题描述:最初使用了错误的路径格式
typescript
// ❌ 错误写法
font.registerFont({
familyName: 'iconfont',
familySrc: 'iconfont.ttf' // 字符串路径
});
// ✅ 正确写法
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf') // 使用 $rawfile() 包装
});
关键点:
- HarmonyOS 中 rawfile 资源必须使用
$rawfile()函数访问 - 字体文件放在
entry/src/main/resources/rawfile/目录下 - 不要使用相对路径字符串
参考文档 :HarmonyOS Font API
第二步:验证 Unicode 编码映射
问题描述:代码中的 Unicode 值与字体文件中的实际编码不匹配
如何验证编码是否正确?
- 找到源 CSS 文件 (通常在 iconfont 下载包中):
css
/* iconfont.css */
.icon-shouye:before {
content: "\e81a"; /* 正确的 Unicode 编码 */
}
.icon-chazhao:before {
content: "\e829";
}
- 对比代码中的映射:
typescript
// ❌ 错误的映射
const iconMap: Record<string, string> = {
'shouye': '\ue601', // 与 CSS 不匹配!
'chazhao': '\ue6ae' // 与 CSS 不匹配!
}
// ✅ 正确的映射
const iconMap: Record<string, string> = {
'shouye': '\ue81a', // 与 CSS 一致
'chazhao': '\ue829' // 与 CSS 一致
}
批量提取正确编码的方法
可以使用正则表达式从 CSS 文件中提取:
bash
# 从 iconfont.css 提取所有图标编码
grep -oP '\.icon-\K[^:]+(?=:before)' iconfont.css
grep -oP 'content: "\K\\[^"]+' iconfont.css
或者查看 iconfont.json 文件:
json
{
"glyphs": [
{
"name": "首页",
"font_class": "shouye",
"unicode": "e81a",
"unicode_decimal": 59418
}
]
}
第三步:检查字体文件版本
问题描述:即使编码正确,图标仍不显示
通过 MD5 校验发现字体文件不匹配:
bash
# 检查字体文件 MD5
md5sum entry/src/main/resources/rawfile/iconfont.ttf
# 输出: 4e1f4122795ebf3c942c4bac45c9f5f8 40KB (错误的文件)
md5sum vue/static/icon/iconfont.ttf
# 输出: 495b2770ac78a7c25a1039931dbe20ac 35KB (正确的文件)
解决方案:从源项目复制正确的字体文件
bash
cp vue/static/icon/iconfont.ttf entry/src/main/resources/rawfile/iconfont.ttf
注意:
- 确保字体文件与 CSS/JSON 配置文件来自同一个 iconfont 下载包
- 不同版本的字体文件可能包含不同的字形
- 更新字体文件后需要 Clean Project 清理构建缓存
第四步:字体注册时机问题(核心问题)
这是最关键的问题! 即使前面都正确,图标可能仍然不显示。
问题分析
typescript
// EntryAbility.ets 中全局注册
export default class EntryAbility extends UIAbility {
onWindowStageCreate(windowStage: window.WindowStage): void {
// 全局注册字体
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
// 加载页面
windowStage.loadContent('pages/Index', (err) => {
// 页面可能在字体注册完成前就开始渲染
});
}
}
问题原因:
- EntryAbility 中的全局注册与页面渲染存在时序问题
- 页面可能在字体完全加载前就开始渲染
- 不同页面的生命周期可能导致字体不可用
解决方案:页面级字体注册
创建工具函数 (common/IconFont.ets):
typescript
import { Font } from '@kit.ArkUI';
/**
* 注册 iconfont 字体
* 在每个需要使用图标的页面的 aboutToAppear 中调用
*/
export function registerIconFont(uiContext: UIContext): void {
try {
const font: Font = uiContext.getFont();
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
console.info('[IconFont] Font registered successfully');
} catch (err) {
console.error('[IconFont] Failed to register font:', JSON.stringify(err));
}
}
/**
* 获取图标字符
*/
export function getIconChar(icon: string): string {
const iconMap: Record<string, string> = {
'shouye': '\ue81a',
'chazhao': '\ue829',
'wendu': '\ue80f',
// ... 其他图标映射
};
return iconMap[icon] || '';
}
在每个页面中使用:
typescript
import { registerIconFont, getIconChar } from '../common/IconFont';
@Entry
@Component
struct MyPage {
aboutToAppear() {
// ✅ 关键:在页面生命周期中注册字体
registerIconFont(this.getUIContext());
// 其他初始化代码...
}
build() {
Column() {
Text(getIconChar('shouye'))
.fontSize(24)
.fontFamily('iconfont') // 现在可以正常显示了!
}
}
}
为什么这样可以解决问题?
- 时序保证:字体在页面组件初始化时注册,确保渲染前字体已可用
- 上下文正确:使用页面自己的 UIContext,避免全局上下文问题
- 重复注册安全:HarmonyOS 允许重复注册同一字体,后续注册会被忽略
- 独立性强:每个页面独立管理字体,不依赖全局状态
完整解决方案
1. 项目结构
entry/src/main/
├── ets/
│ ├── common/
│ │ └── IconFont.ets # 字体工具函数
│ ├── pages/
│ │ ├── Index.ets # 使用字体的页面
│ │ └── LoginPage.ets
│ └── entryability/
│ └── EntryAbility.ets # 可选的全局注册
└── resources/
└── rawfile/
├── iconfont.ttf # 字体文件
├── iconfont.css # 编码参考
└── iconfont.json # 元数据
2. IconFont.ets 工具文件
typescript
import { Font } from '@kit.ArkUI';
/**
* 注册 iconfont 字体
* 必须在每个页面的 aboutToAppear 中调用
*/
export function registerIconFont(uiContext: UIContext): void {
try {
const font: Font = uiContext.getFont();
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
console.info('[IconFont] Font registered successfully');
} catch (err) {
console.error('[IconFont] Failed to register font:', JSON.stringify(err));
}
}
/**
* 图标映射表(从 iconfont.css 提取)
*/
const iconMap: Record<string, string> = {
// 导航图标
'shouye': '\ue81a', // 首页
'chazhao': '\ue829', // 搜索
'touxiang': '\ue602', // 用户
'downshow': '\ue608', // 下拉
'upshow': '\ue609', // 上拉
// 功能图标
'wendu': '\ue80f', // 体温
'yaoping': '\ue820', // 药瓶
'zhushe': '\ue816', // 注射
'shuye': '\ue91f', // 输液
// 系统图标
'right': '\ue627', // 右箭头
'left': '\ue626', // 左箭头
'guanbi': '\ue61e', // 关闭
'gengxin': '\ue628', // 更新
'tuichu': '\ue632', // 退出
// ... 添加所有图标映射
};
/**
* 获取图标字符
*/
export function getIconChar(icon: string): string {
return iconMap[icon] || '';
}
/**
* IconFont 组件(可选)
*/
@Component
export struct IconFont {
@Prop icon: string = '';
@Prop fontSize: number = 20;
@Prop color: string = '#000000';
build() {
Text(getIconChar(this.icon))
.fontSize(this.fontSize)
.fontColor(this.color)
.fontFamily('iconfont')
}
}
3. 页面中使用
方式一:使用工具函数(推荐)
typescript
import { registerIconFont, getIconChar } from '../common/IconFont';
@Entry
@Component
struct HomePage {
aboutToAppear() {
// 必须:注册字体
registerIconFont(this.getUIContext());
}
build() {
Column() {
// 方式1:直接使用 Text
Text(getIconChar('shouye'))
.fontSize(24)
.fontColor('#0092A1')
.fontFamily('iconfont')
// 方式2:在 Row 中使用
Row() {
Text(getIconChar('chazhao'))
.fontSize(20)
.fontFamily('iconfont')
.margin({ right: 10 })
Text('搜索')
.fontSize(16)
}
}
}
}
方式二:使用 IconFont 组件
typescript
import { registerIconFont, IconFont } from '../common/IconFont';
@Entry
@Component
struct HomePage {
aboutToAppear() {
registerIconFont(this.getUIContext());
}
build() {
Column() {
IconFont({
icon: 'shouye',
fontSize: 24,
color: '#0092A1'
})
IconFont({
icon: 'chazhao',
fontSize: 20
})
}
}
}
4. 常见使用场景
TabBar 图标
typescript
@Builder
buildTabBar(title: string, index: number, iconName: string) {
Column() {
Text(getIconChar(iconName))
.fontSize(24)
.fontColor(this.currentIndex === index ? '#0092A1' : '#666666')
.fontFamily('iconfont')
Text(title)
.fontSize(12)
.fontColor(this.currentIndex === index ? '#0092A1' : '#666666')
.margin({ top: 4 })
}
}
按钮图标
typescript
Button() {
Row() {
Text(getIconChar('gengxin'))
.fontSize(16)
.fontColor(Color.White)
.fontFamily('iconfont')
.margin({ right: 5 })
Text('更新')
.fontSize(14)
.fontColor(Color.White)
}
}
.backgroundColor('#0092A1')
列表项图标
typescript
Row() {
Text(getIconChar('right'))
.fontSize(14)
.fontFamily('iconfont')
.fontColor('#999999')
}
调试技巧
1. 创建字体测试页面
typescript
import { registerIconFont, getIconChar } from '../common/IconFont';
import { font } from '@kit.ArkUI';
@Entry
@Component
struct FontTestPage {
@State fontStatus: string = '准备注册字体...';
@State testIcons: string[] = ['shouye', 'chazhao', 'wendu', 'yaoping'];
aboutToAppear() {
try {
// 注册字体
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
this.fontStatus = '✅ 字体注册成功';
} catch (err) {
this.fontStatus = '❌ 字体注册失败: ' + JSON.stringify(err);
}
}
build() {
Scroll() {
Column() {
Text('iconfont 显示测试')
.fontSize(20)
.fontWeight(FontWeight.Bold)
.margin({ top: 20, bottom: 20 })
Text(this.fontStatus)
.fontSize(14)
.fontColor(this.fontStatus.includes('成功') ? '#4CAF50' : '#FF6B6B')
.margin({ bottom: 30 })
// 测试1: 直接 Unicode
Text('测试1: 直接 Unicode')
.fontSize(16)
.margin({ top: 20, bottom: 10 })
Row({ space: 20 }) {
Text('\ue81a')
.fontSize(32)
.fontFamily('iconfont')
.border({ width: 1, color: '#FF6B6B' })
.padding(10)
Text('应显示"首页"图标')
.fontSize(12)
}
// 测试2: getIconChar 函数
Text('测试2: getIconChar 函数')
.fontSize(16)
.margin({ top: 20, bottom: 10 })
Row({ space: 20 }) {
Text(getIconChar('shouye'))
.fontSize(32)
.fontFamily('iconfont')
.border({ width: 1, color: '#4CAF50' })
.padding(10)
Text('应显示"首页"图标')
.fontSize(12)
}
// 测试3: 多个图标
Text('测试3: 多个图标')
.fontSize(16)
.margin({ top: 20, bottom: 10 })
GridRow({ columns: 4, gutter: { x: 10, y: 10 } }) {
ForEach(this.testIcons, (iconName: string) => {
GridCol() {
Column() {
Text(getIconChar(iconName))
.fontSize(32)
.fontFamily('iconfont')
.border({ width: 1, color: '#0092A1' })
.width(60)
.height(60)
.textAlign(TextAlign.Center)
Text(iconName)
.fontSize(10)
.margin({ top: 5 })
}
}
})
}
// 测试4: 不指定 fontFamily
Text('测试4: 不指定 fontFamily')
.fontSize(16)
.margin({ top: 20, bottom: 10 })
Text('\ue81a')
.fontSize(32)
.border({ width: 1, color: '#FFA500' })
.padding(10)
Text('← 不指定 fontFamily,应显示空白方框')
.fontSize(12)
.fontColor('#FFA500')
// 测试5: 普通文字
Text('测试5: 普通文字')
.fontSize(16)
.margin({ top: 20, bottom: 10 })
Text('测试文字 ABC 123')
.fontSize(16)
.fontFamily('iconfont')
.border({ width: 1, color: '#999999' })
.padding(10)
Text('← 用 iconfont 显示文字')
.fontSize(12)
}
.width('100%')
.padding(20)
}
}
}
2. 日志调试
typescript
// 在 aboutToAppear 中添加详细日志
aboutToAppear() {
console.info('===== 页面开始初始化 =====');
try {
const uiContext = this.getUIContext();
console.info('UIContext 获取成功');
const font = uiContext.getFont();
console.info('Font 对象获取成功');
registerIconFont(uiContext);
console.info('字体注册完成');
} catch (error) {
console.error('字体注册失败:', JSON.stringify(error));
}
console.info('===== 页面初始化完成 =====');
}
3. 检查构建产物
bash
# 清理构建缓存
rm -rf entry/build
# 或使用 DevEco Studio
Build → Clean Project
# 重新构建
Build → Rebuild Project
4. 验证字体文件
bash
# 检查文件是否存在
ls -lh entry/src/main/resources/rawfile/iconfont.ttf
# 验证 MD5(与源文件对比)
md5sum entry/src/main/resources/rawfile/iconfont.ttf
md5sum path/to/original/iconfont.ttf
# 查看字体文件信息(macOS/Linux)
otfinfo -i iconfont.ttf
常见问题 FAQ
Q1: 为什么有的图标显示正常,有的显示空白?
A: Unicode 编码映射不完整或错误。
解决方法:
- 检查
iconMap中是否包含该图标的映射 - 验证 Unicode 值是否与 CSS 文件一致
- 确认字体文件中包含该字形
typescript
// 添加缺失的图标映射
const iconMap: Record<string, string> = {
'missing-icon': '\uexxx', // 从 CSS 中找到正确编码
// ...
};
Q2: 在模拟器上正常,真机上不显示?
A: 可能是字体文件打包问题。
解决方法:
- 确认
rawfile目录结构正确 - 检查
module.json5中没有排除 rawfile 资源 - Clean Project 后重新构建
- 确认字体文件大小正常(不是 0 字节)
Q3: 字体文件很大,如何优化?
A: 只保留需要的字形。
解决方法:
- 在 iconfont.cn 重新选择需要的图标
- 下载精简版字体文件
- 或使用工具裁剪字体文件:
bash
# 使用 fonttools 裁剪字体(Python)
pip install fonttools
pyftsubset iconfont.ttf \
--unicodes="U+e81a,U+e829,U+e80f" \
--output-file="iconfont-subset.ttf"
Q4: 可以在组件中使用吗?
A: 可以,但需要正确传递 UIContext。
typescript
@Component
export struct MyComponent {
aboutToAppear() {
// 组件也需要注册字体
registerIconFont(this.getUIContext());
}
build() {
Text(getIconChar('shouye'))
.fontFamily('iconfont')
}
}
Q5: 动态加载字体文件?
A: 当前不支持运行时动态加载,字体必须在编译时打包。
替代方案:
- 使用 Image 组件加载 SVG
- 使用系统图标库
- 预先打包多个字体文件切换使用
Q6: 字体注册失败,提示权限错误?
A : 检查 module.json5 权限配置。
json5
{
"module": {
"requestPermissions": [
// 不需要特殊权限访问 rawfile
]
}
}
如果仍有问题,检查文件路径:
- ✅
$rawfile('iconfont.ttf') - ❌
$rawfile('/iconfont.ttf') - ❌
$rawfile('fonts/iconfont.ttf')(除非你创建了子目录)
最佳实践总结
✅ 推荐做法
-
每个页面独立注册字体
typescriptaboutToAppear() { registerIconFont(this.getUIContext()); } -
使用工具函数统一管理
- 创建
common/IconFont.ets统一管理 - 所有图标映射集中维护
- 提供类型安全的访问方式
- 创建
-
从源文件提取编码
- 始终以
iconfont.css为准 - 不要手动猜测 Unicode 值
- 使用脚本自动提取
- 始终以
-
版本控制字体文件
- 将字体文件纳入版本控制
- 记录 iconfont 项目 ID 和下载时间
- 保留 CSS/JSON 配置文件用于查询
-
创建测试页面
- 开发阶段保留字体测试页面
- 方便验证新增图标
- 快速定位显示问题
❌ 避免的做法
-
不要只在 EntryAbility 中注册
typescript// ❌ 不可靠 export default class EntryAbility extends UIAbility { onWindowStageCreate() { font.registerFont(...); // 时序问题 } } -
不要使用硬编码 Unicode
typescript// ❌ 维护困难 Text('\ue81a') // ✅ 使用语义化名称 Text(getIconChar('shouye')) -
不要忘记 fontFamily
typescript// ❌ 不会显示 Text(getIconChar('shouye')) // ✅ 必须指定 fontFamily Text(getIconChar('shouye')) .fontFamily('iconfont') -
不要混用多个字体文件
- 容易造成编码冲突
- 增加应用体积
- 如需多套图标,考虑使用不同 familyName
-
不要跳过 Clean Build
- 更新字体文件后必须清理缓存
- 否则可能使用旧的字体文件
工具脚本
从 CSS 提取 Unicode 映射
python
#!/usr/bin/env python3
# extract_iconmap.py
import re
import sys
def extract_icon_map(css_file):
"""从 iconfont.css 提取图标映射"""
with open(css_file, 'r', encoding='utf-8') as f:
content = f.read()
# 匹配 .icon-xxx:before { content: "\exxx"; }
pattern = r'\.icon-([^:]+):before\s*\{\s*content:\s*"\\([^"]+)"'
matches = re.findall(pattern, content)
print("// 从", css_file, "提取的图标映射")
print("const iconMap: Record<string, string> = {")
for name, unicode in matches:
# 转换为 TypeScript 格式
print(f" '{name}': '\\u{unicode}',")
print("};")
print(f"\n// 总共 {len(matches)} 个图标")
if __name__ == '__main__':
if len(sys.argv) < 2:
print("用法: python extract_iconmap.py iconfont.css")
sys.exit(1)
extract_icon_map(sys.argv[1])
使用方法:
bash
python extract_iconmap.py entry/src/main/resources/rawfile/iconfont.css > icon_map.txt
验证字体文件完整性
bash
#!/bin/bash
# check_font.sh
FONT_FILE="entry/src/main/resources/rawfile/iconfont.ttf"
CSS_FILE="entry/src/main/resources/rawfile/iconfont.css"
echo "===== 字体文件检查 ====="
# 检查文件是否存在
if [ ! -f "$FONT_FILE" ]; then
echo "❌ 字体文件不存在: $FONT_FILE"
exit 1
fi
if [ ! -f "$CSS_FILE" ]; then
echo "⚠️ CSS 文件不存在: $CSS_FILE"
fi
# 文件大小
SIZE=$(ls -lh "$FONT_FILE" | awk '{print $5}')
echo "✅ 字体文件大小: $SIZE"
# MD5
MD5=$(md5sum "$FONT_FILE" | awk '{print $1}')
echo "✅ 字体文件 MD5: $MD5"
# 统计 CSS 中图标数量
if [ -f "$CSS_FILE" ]; then
ICON_COUNT=$(grep -c "\.icon-" "$CSS_FILE")
echo "✅ CSS 定义图标数: $ICON_COUNT"
fi
# 检查 rawfile 目录权限
PERMS=$(stat -c "%a" "$FONT_FILE" 2>/dev/null || stat -f "%p" "$FONT_FILE" | tail -c 4)
echo "✅ 文件权限: $PERMS"
echo "===== 检查完成 ====="
性能优化建议
1. 字体文件优化
typescript
// 按需加载(如果有多个页面模块)
class FontManager {
private static loaded: Set<string> = new Set();
static registerOnce(uiContext: UIContext, fontName: string = 'iconfont') {
if (this.loaded.has(fontName)) {
console.info(`[FontManager] ${fontName} already loaded`);
return;
}
try {
const font = uiContext.getFont();
font.registerFont({
familyName: fontName,
familySrc: $rawfile(`${fontName}.ttf`)
});
this.loaded.add(fontName);
console.info(`[FontManager] ${fontName} registered`);
} catch (err) {
console.error(`[FontManager] Failed to register ${fontName}:`, err);
}
}
}
// 使用
aboutToAppear() {
FontManager.registerOnce(this.getUIContext());
}
2. 图标组件缓存
typescript
@Component
export struct CachedIconFont {
@Prop icon: string;
@Prop fontSize: number = 20;
@Prop color: string = '#000000';
// 缓存字符,避免重复查询
@State private cachedChar: string = '';
aboutToAppear() {
this.cachedChar = getIconChar(this.icon);
}
build() {
Text(this.cachedChar)
.fontSize(this.fontSize)
.fontColor(this.color)
.fontFamily('iconfont')
}
}
3. 减少重复注册
typescript
// 使用单例模式
class IconFontLoader {
private static instance: IconFontLoader;
private loaded: boolean = false;
private constructor() {}
static getInstance(): IconFontLoader {
if (!IconFontLoader.instance) {
IconFontLoader.instance = new IconFontLoader();
}
return IconFontLoader.instance;
}
register(uiContext: UIContext): void {
if (this.loaded) return;
try {
const font = uiContext.getFont();
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
this.loaded = true;
} catch (err) {
console.error('Font registration failed:', err);
}
}
}
// 使用
aboutToAppear() {
IconFontLoader.getInstance().register(this.getUIContext());
}
总结
iconfont 在 HarmonyOS 中的使用核心要点:
- 路径格式 :必须使用
$rawfile('iconfont.ttf') - Unicode 映射:必须与 CSS 文件中的编码完全一致
- 字体文件:确保使用正确版本的字体文件
- 注册时机 :✨ 在每个页面的
aboutToAppear()中注册字体(最重要!) - fontFamily :使用图标时必须指定
.fontFamily('iconfont')
通过本文的实践,你应该能够:
- ✅ 正确集成 iconfont 到 HarmonyOS 应用
- ✅ 快速定位图标不显示的问题
- ✅ 建立可维护的图标管理方案
- ✅ 避免常见的字体加载陷阱
希望这篇文章能帮助你在 HarmonyOS 开发中顺利使用 iconfont!
参考资源
- HarmonyOS Font API 文档
- ArkUI 字体相关问题
- iconfont 官网
- 本项目 GitHub: [附上你的项目地址]
作者 :[你的名字]
日期 :2025-01-05
HarmonyOS 版本 :5.0.0 (API 12)
DevEco Studio 版本:5.0.3.500
附录:完整代码示例
IconFont.ets 完整代码
typescript
import { Font } from '@kit.ArkUI';
/**
* 注册 iconfont 字体
* 在每个需要使用图标的页面的 aboutToAppear 中调用
*/
export function registerIconFont(uiContext: UIContext): void {
try {
const font: Font = uiContext.getFont();
font.registerFont({
familyName: 'iconfont',
familySrc: $rawfile('iconfont.ttf')
});
console.info('[IconFont] Font registered successfully');
} catch (err) {
console.error('[IconFont] Failed to register font:', JSON.stringify(err));
}
}
/**
* IconFont 字体图标组件
* 使用方法: IconFont({ icon: 'chazhao', size: 20, color: '#333' })
*/
@Component
export struct IconFont {
@Prop icon: string = '';
@Prop fontSize: number = 20;
@Prop color: string = '#000000';
private uiContext: UIContext | null = null;
private font: Font | null = null;
// 组件初始化(字体已在页面 aboutToAppear 中注册)
aboutToAppear() {
this.uiContext = this.getUIContext();
this.font = this.uiContext.getFont();
}
// iconfont 字符映射表(从 iconfont.css 提取)
private iconMap: Record<string, string> = {
// 常用图标
'chazhao': '\ue829', // 查找
'shouye': '\ue81a', // 首页
'touxiang': '\ue602', // 头像
'downshow': '\ue608', // 下拉
'upshow': '\ue609', // 上拉
'qiehuanyonghu': '\ue6ed', // 切换用户
'guanbi': '\ue61e', // 关闭
// 功能模块图标
'wendu': '\ue80f', // 体温
'yaopian': '\ue822', // 药片(出入量)
'youzhi': '\ue81c', // 血糖
'yaoping': '\ue820', // 药瓶(病区收药/口服)
'xietong': '\ue61a', // 血酮
'binglizhuanyunjilu1': '\ue615', // 转运接收
'a-wenjianjiawenjian1': '\ue726', // 护理文件
'dingdan': '\ue82a', // 订单/记录
// 执行中心图标
'shuye': '\ue91f', // 输液
'zhushe': '\ue816', // 注射
'pifu': '\ue987', // 皮试
'tianjiaji': '\ue821', // 雾化
'yaoxiang': '\ue815', // 护理
'renzheng': '\ue826', // 治疗
'quanke': '\ue81f', // 其他
'shoushudao': '\ue920', // 手术
'huayanke': '\ue828', // 标本
'shiguan': '\ue81d', // 检查
'shuxie': '\ue9aa', // 输血
// 系统功能图标
'daijiaolao': '\ue67b', // 带教老师
'keshi': '\ue69d', // 科室
'gengxin': '\ue628', // 更新
'qinglihuancun': '\ue631', // 清理缓存
'tuichu': '\ue632', // 退出
'a-bianzu62x': '\ue607', // 筛选
// 导航图标
'right': '\ue627', // 右箭头
'left': '\ue626', // 左箭头
'top': '\ue646', // 上箭头
'bottom': '\ue647', // 下箭头
}
build() {
Text(this.getIconChar())
.fontSize(this.fontSize)
.fontColor(this.color)
.fontFamily('iconfont')
}
private getIconChar(): string {
return this.iconMap[this.icon] || '';
}
}
/**
* 获取图标字符(用于非组件场景)
*/
export function getIconChar(icon: string): string {
const iconMap: Record<string, string> = {
'chazhao': '\ue829',
'shouye': '\ue81a',
'touxiang': '\ue602',
'downshow': '\ue608',
'upshow': '\ue609',
'qiehuanyonghu': '\ue6ed',
'guanbi': '\ue61e',
'wendu': '\ue80f',
'yaopian': '\ue822',
'youzhi': '\ue81c',
'yaoping': '\ue820',
'xietong': '\ue61a',
'binglizhuanyunjilu1': '\ue615',
'a-wenjianjiawenjian1': '\ue726',
'dingdan': '\ue82a',
'shuye': '\ue91f',
'zhushe': '\ue816',
'pifu': '\ue987',
'tianjiaji': '\ue821',
'yaoxiang': '\ue815',
'renzheng': '\ue826',
'quanke': '\ue81f',
'shoushudao': '\ue920',
'huayanke': '\ue828',
'shiguan': '\ue81d',
'shuxie': '\ue9aa',
'daijiaolao': '\ue67b',
'keshi': '\ue69d',
'gengxin': '\ue628',
'qinglihuancun': '\ue631',
'tuichu': '\ue632',
'a-bianzu62x': '\ue607',
'right': '\ue627',
'left': '\ue626',
'top': '\ue646',
'bottom': '\ue647',
};
return iconMap[icon] || '';
}