/** * 小程序字体缩放适配 * * 字号来源优先级:用户手动设置 > 微信系统字号(fontSizeScaleFactor / fontSizeSetting)> 1(默认) * 值域钳制在 [0.9, 1.7],超出视为无效值按默认处理。 * * 平台差异说明(微信体系,基于 uni.getAppBaseInfo()): * - fontSizeScaleFactor:缩放比例(直接可用) * - fontSizeSetting:用户设置的字号 px 值(基准 16px),需基础库 2.23.4+ * - rpx 不随字号变化,需手动乘系数才能让正文跟随用户设置 */ // --- 读取微信系统字号系数(单次调用) --- export function readSystemFontScale() { try { if (typeof uni !== 'undefined' && uni.getAppBaseInfo) { const baseInfo = uni.getAppBaseInfo() if (baseInfo) { // 优先:直接缩放比例(微信基础库 >= 2.23.4 支持) if (typeof baseInfo.fontSizeScaleFactor === 'number' && !isNaN(baseInfo.fontSizeScaleFactor)) { return baseInfo.fontSizeScaleFactor } // 降级:原始 px 值除以基准 16px if (typeof baseInfo.fontSizeSetting === 'number' && !isNaN(baseInfo.fontSizeSetting)) { const scale = baseInfo.fontSizeSetting / 16 if (scale > 0) return scale } } } } catch (e) { // ignore } try { if (typeof wx !== 'undefined' && wx.getAppBaseInfo) { const baseInfo = wx.getAppBaseInfo() if (baseInfo) { if (typeof baseInfo.fontSizeScaleFactor === 'number' && !isNaN(baseInfo.fontSizeScaleFactor)) { return baseInfo.fontSizeScaleFactor } if (typeof baseInfo.fontSizeSetting === 'number' && !isNaN(baseInfo.fontSizeSetting)) { const scale = baseInfo.fontSizeSetting / 16 if (scale > 0) return scale } } } } catch (e) { // ignore } return 1 } // --- 钳制系数到 [0.9, 1.7] 并返回保留两位小数的值 --- function clampAndRound(scale) { if (typeof scale !== 'number' || isNaN(scale) || scale <= 0) return 1 if (scale < 0.9) scale = 0.9 if (scale > 1.7) scale = 1.7 return Math.round(scale * 100) / 100 } // --- 读取用户手动设置的字号系数(storage 持久化) --- export function getUserFontScale() { try { const stored = uni.getStorageSync('userFontScale') if (typeof stored === 'number' && !isNaN(stored) && stored > 0) { return clampAndRound(stored) } } catch (e) { // ignore } return null // null 表示未设置 } // --- 写入用户手动设置的字号系数 --- export function setUserFontScale(scale) { let s = clampAndRound(scale) try { uni.setStorageSync('userFontScale', s) } catch (e) { // ignore } return s } // --- 对外接口:读取当前生效字号系数 --- export function getFontScale() { // 优先用户设置 const user = getUserFontScale() if (user !== null) return user // 其次 storage 中的系统系数(上次同步留下的缓存) try { const stored = uni.getStorageSync('fontSizeScaleFactor') if (typeof stored === 'number' && !isNaN(stored) && stored > 0) { return clampAndRound(stored) } } catch (e) { // ignore } // 最终:实时从系统读取 return clampAndRound(readSystemFontScale()) } // --- 同步(冷启动 / 每次回到前台)--- export function syncFontScale() { const systemScale = readSystemFontScale() const scale = clampAndRound(systemScale) try { // 仅在用户未手动设置时写入 storage,避免把系统值覆盖掉用户的自定义偏好 if (getUserFontScale() === null) { uni.setStorageSync('fontSizeScaleFactor', scale) } } catch (e) { // ignore } return scale } // --- 构建 mp-html 标签默认样式(用于 p/div/section/li/blockquote 等正文标签) // baseFontSize: 基准字号 rpx(推荐 28~32),例如文章/商品介绍正文用 32 // scale: 当前生效字号系数(调用 getFontScale() 获取) // 返回 tagStyle 对象,可直接传给 export function buildContentTagStyle(baseFontSize, scale) { const s = typeof scale === 'number' ? scale : 1 const size = Math.round(baseFontSize * s) return { p: 'font-size:' + size + 'rpx;color:#444;line-height:1.8;', div: 'font-size:' + size + 'rpx;color:#444;line-height:1.8;', section: 'font-size:' + size + 'rpx;color:#444;line-height:1.8;', li: 'font-size:' + size + 'rpx;color:#444;line-height:1.8;', blockquote: 'font-size:' + size + 'rpx;color:#666;line-height:1.7;' } }