fix: fc-icon 改用 SVG 矢量图 + image 渲染,彻底解决微信 text 自定义字体不显示导致图标变字符
- 微信小程序 <text> 对 @font-face 自定义字体支持不可靠(开发者工具/真机均可能不渲染),图标回退成字符 - 改用 <image> 渲染 Lucide SVG 矢量图(data:image/svg+xml),彻底绕开字体加载限制,矢量/可上色 - 新增 utils/icon-svg.js(49 图标内层 SVG,stroke/fill 用 __C__ 占位),fc-icon 按 color 动态拼色 - 内置设计 token→色值映射,调用方传 var(--xxx) 自动解析为具体色值 - 移除 app.wxss 中已无用的 @font-face(字体方案废弃)
This commit is contained in:
@@ -1,23 +1,54 @@
|
||||
const iconMap = require('../../utils/icon-map');
|
||||
const iconSvg = require('../../utils/icon-svg');
|
||||
|
||||
// 设计 token 色值映射:调用方常传 var(--xxx),但 SVG data URI 内无法解析 CSS 变量,需转成具体色值
|
||||
const CSS_VARS = {
|
||||
'--accent': '#B6F24E',
|
||||
'--accent-hover': '#C7F56E',
|
||||
'--accent-active': '#9EDB3A',
|
||||
'--text': '#ECF1EF',
|
||||
'--text-2': '#9BA7A1',
|
||||
'--text-3': '#6B7670',
|
||||
'--danger': '#FF5C5C',
|
||||
'--success': '#2BD9A6',
|
||||
'--warn': '#F2B53D',
|
||||
'--info': '#4FA8FF',
|
||||
};
|
||||
function resolveColor(c) {
|
||||
if (!c) return '#ECF1EF';
|
||||
const m = /^var\((--[\w-]+)\)$/.exec(String(c).trim());
|
||||
if (m) return CSS_VARS[m[1]] || '#ECF1EF';
|
||||
return c; // 已是具体色值(hex)
|
||||
}
|
||||
|
||||
// 用 <image> 渲染 Lucide SVG 矢量图(微信小程序 <text> 自定义字体不可靠,改用此方案 100% 稳定)
|
||||
Component({
|
||||
properties: {
|
||||
// Lucide 图标名,如 search / dumbbell / heart
|
||||
name: { type: String, value: '' },
|
||||
// 字号(rpx)
|
||||
// 字号(rpx),同时作为图标宽高
|
||||
size: { type: Number, value: 20 },
|
||||
// 颜色,默认跟随当前文字色(currentColor 在 iconfont 下用具体色)
|
||||
// 颜色:可传具体 hex,或 var(--xxx)(自动解析为对应 token 色值)
|
||||
color: { type: String, value: '' },
|
||||
},
|
||||
data: { glyph: '' },
|
||||
data: { src: '' },
|
||||
observers: {
|
||||
name(n) {
|
||||
this.setData({ glyph: (iconMap[n] || '') });
|
||||
},
|
||||
name(n) { this._build(n, this.data.color); },
|
||||
color(c) { this._build(this.data.name, c); },
|
||||
},
|
||||
lifetimes: {
|
||||
attached() {
|
||||
this.setData({ glyph: (iconMap[this.data.name] || '') });
|
||||
attached() { this._build(this.data.name, this.data.color); },
|
||||
},
|
||||
methods: {
|
||||
_build(name, color) {
|
||||
const inner = iconSvg[name];
|
||||
if (!inner) { this.setData({ src: '' }); return; }
|
||||
const stroke = resolveColor(color);
|
||||
const body = inner.replace(/__C__/g, stroke);
|
||||
const svg =
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" ' +
|
||||
'stroke="' + stroke + '" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' +
|
||||
body + '</svg>';
|
||||
this.setData({ src: 'data:image/svg+xml,' + encodeURIComponent(svg) });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
<text class="fc-icon" style="font-size:{{size}}rpx;{{color ? 'color:' + color + ';' : ''}}">{{glyph}}</text>
|
||||
<image wx:if="{{src}}" src="{{src}}" mode="aspectFit" class="fc-icon" style="width:{{size}}rpx;height:{{size}}rpx;" />
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
.fc-icon {
|
||||
font-family: "fc-icon";
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user