/** * 食材图标 URL(Twemoji PNG,小程序 / H5 通用) * 微信小程序 不支持 SVG data URL,必须用 https PNG */ const TWEMOJI_BASE = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/72x72' /** emoji → Twemoji PNG 地址 */ export function emojiToTwemojiUrl(emoji) { if (!emoji) return '' const parts = [] for (let i = 0; i < emoji.length;) { const cp = emoji.codePointAt(i) if (!cp) break parts.push(cp.toString(16)) i += cp > 0xffff ? 2 : 1 } return `${TWEMOJI_BASE}/${parts.join('-')}.png` } const imgCache = {} export function getFoodImgUrl(emoji) { if (!emoji) return '' if (imgCache[emoji]) return imgCache[emoji] const url = emojiToTwemojiUrl(emoji) imgCache[emoji] = url return url } /** 预加载本局食材图标(小程序提前拉取,减少首屏空白) */ export function warmUpFoodImgs(foods) { const list = Array.isArray(foods) ? foods : [] list.forEach((f) => { const icon = typeof f === 'string' ? f : f?.icon // 优先预热自定义图片素材,缺省回退 emoji PNG const url = (typeof f === 'object' && f?.img) ? f.img : getFoodImgUrl(icon) if (!url) return // #ifdef MP-WEIXIN try { uni.getImageInfo({ src: url, fail: () => {} }) } catch (_) {} // #endif // #ifdef H5 try { const img = new Image() img.src = url } catch (_) {} // #endif }) }