feat(fe): 引入线性图标体系,tabBar 去 emoji,清掉 172KB 死资源

图标不走字体走 mask-image。Tabler 的 outline 图标是 stroke+fill:none,
字形只认填充轮廓,直接转字体会生成空字形——真机表现和「字体没加载」
一模一样,很容易往错方向排查。mask 走渲染 alpha,描边正常参与,
同样支持 currentColor 染色,没有这个坑。

- styles/iconfont.wxss:38 个图标内联 base64,19.9KB
- components/pt-icon:name 支持图标名 / 记录类型 / 老数据里的 emoji,
  三层降级兜底,绝不留空白;virtualHost 避免多一层节点破坏 flex
- custom-tab-bar:🏠📅✍️📊🐾 换成图标,顺手把抄了一遍的三个色值换回 var()
- project.config.json:packOptions.ignore 排掉 preview.html、6 个候选 logo
  等 172KB 死资源,之前它们全打进包里

preview-v2.html 是设计验证页,本身也不参与打包。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-07-29 10:28:48 +08:00
parent 9adafb1354
commit b4a4a4b3c0
11 changed files with 263 additions and 13 deletions
+59
View File
@@ -0,0 +1,59 @@
// 线性图标。图标资源在 styles/iconfont.wxssmask-image + currentColor)。
//
// name 可以直接传图标名,也可以传服务端下发的值:
// - 记录类型(HealthRecord.Type9 值枚举,可靠)
// - 文章分类(Article.Category
// - 历史 emoji(老数据里 icon 字段存的就是 emoji,只能兜底映射)
// 三层都命不中时退到 fallback(默认 note),绝不留空白。
// 记录类型 / 文章分类 → 图标名
const BY_TYPE = {
weight: 'weight',
poop: 'poop',
food: 'food',
symptom: 'symptom',
medicine: 'medicine',
vaccine: 'vaccine',
deworm: 'deworm',
cost: 'cost',
photo: 'photo',
note: 'doc',
};
// 老数据里存的 emoji → 图标名。新数据不再写 emoji,但历史记录得能正常显示
const BY_EMOJI = {
'⚖️': 'weight', '⚖': 'weight',
'💩': 'poop',
'🍽️': 'food', '🍽': 'food', '🍚': 'food',
'🤒': 'symptom', '🌡️': 'symptom',
'💊': 'medicine',
'💰': 'cost', '💸': 'cost',
'📷': 'photo', '📸': 'photo',
'💉': 'vaccine',
'🛡️': 'deworm', '🛡': 'deworm',
'📄': 'doc', '📋': 'doc',
'📝': 'note', '✍️': 'note', '✍': 'note',
'🐱': 'cat', '🐶': 'dog', '🐾': 'community',
'🔔': 'bell', '⚙️': 'settings', '⚙': 'settings',
'📅': 'plan', '📊': 'report', '🏠': 'home',
'⚠️': 'warn', '📖': 'book', '📚': 'book',
};
Component({
options: { addGlobalClass: true, virtualHost: true },
properties: {
name: { type: String, value: '' },
size: { type: Number, value: 32 }, // rpx
color: { type: String, value: '' }, // 留空则跟随父级文字色
fallback: { type: String, value: 'note' },
},
data: { cls: '', style: '' },
observers: {
'name,size,color,fallback': function (name, size, color, fallback) {
const n = BY_TYPE[name] || BY_EMOJI[name] || name || fallback;
const style =
'width:' + size + 'rpx;height:' + size + 'rpx' + (color ? ';background-color:' + color : '');
this.setData({ cls: 'pt-i pt-i-' + n, style });
},
},
});
+4
View File
@@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}
+1
View File
@@ -0,0 +1 @@
<view class="{{cls}}" style="{{style}}"></view>
+17
View File
@@ -0,0 +1,17 @@
/* 图标资源在组件内 import:这样 mask 定义和用它的节点在同一个样式作用域,
不受组件样式隔离影响,custom-tab-bar 这种没开 addGlobalClass 的地方也能直接用。 */
@import "../../styles/iconfont.wxss";
.pt-i {
display: inline-block;
flex: none;
background-color: currentColor;
-webkit-mask-image: var(--m);
mask-image: var(--m);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}