UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

223 lines (222 loc) 9.32 kB
/** * 响应式缩放系数(--nut-scale-f):结合京东站内原生桥与站外视口规则, * 写入根节点 CSS 变量(--nut-scale-f / --nut-scale-font / --nut-scale-icon), * 供布局/字号/icon 等按比例换算(见 calcByProfile)。H5 与 Taro WebView 共用此实现。 */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: Object.getOwnPropertyDescriptor(all, name).get }); } _export(exports, { get calcByProfile () { return calcByProfile; }, get initScaleF () { return initScaleF; } }); var _async_to_generator = require("@swc/helpers/_/_async_to_generator"); var _ts_generator = require("@swc/helpers/_/_ts_generator"); var _canusedom = require("./can-use-dom"); /** 当前基准缩放(来自原生或视口计算) */ var scale = 1; /** 大字模式下仅 font 场景的相对倍率 */ var LARGE_FONT_RATIO = 1.15; /** 老年模式下 font/icon/lego 场景的相对倍率 */ var ELDERLY_RATIO = 1.3; /** 全局当前档位,与 scale 共同参与 calcByProfile */ var profile = 'standard'; /** 仅 large / elderly 有效,其余一律视为 standard */ function normalizeProfile(nextProfile) { if (nextProfile === 'large' || nextProfile === 'elderly') return nextProfile; return 'standard'; } /** 计算 CSS 变量要使用的场景缩放(基准 scale × 场景倍率) */ function getCssSceneScale(scene, baseScale) { return baseScale * getSceneRatio(scene, profile); } /** 将缩放值同步到 :root 的 --nut-scale-f / --nut-scale-font / --nut-scale-icon */ function applyScaleCssVars(nextScale) { if (!_canusedom.canUseDom) return; var rootStyle = document.documentElement.style; rootStyle.setProperty('--nut-scale-f', formatScaleValue(nextScale)); rootStyle.setProperty('--nut-scale-font', formatScaleValue(getCssSceneScale('font', nextScale))); rootStyle.setProperty('--nut-scale-icon', formatScaleValue(getCssSceneScale('icon', nextScale))); } /** >1 保留两位小数字符串;否则取整,与 CSS 消费端约定一致 */ function formatScaleValue(nextScale) { if (nextScale > 1) { return (Math.round(nextScale * 100) / 100).toFixed(2); } return "".concat(Math.round(nextScale)); } /** 根据屏宽粗略区分 phone / pad */ function getCurrentDevice() { if (!_canusedom.canUseDom) return 'phone'; return window.innerWidth >= 600 ? 'pad' : 'phone'; } /** 在 profile 与 scene 维度上叠加额外倍率(与全局 scale 相乘) */ function getSceneRatio(scene, currentProfile) { if (currentProfile === 'elderly' && (scene === 'font' || scene === 'icon' || scene === 'lego')) { return ELDERLY_RATIO; } if (currentProfile === 'large' && scene === 'font') { return LARGE_FONT_RATIO; } return 1; } /** 输出 px 等单位时的取整规则:缩放>1 或强制时保留两位小数精度 */ function roundByScaleRule(value, baseScale) { var forceKeepTwoDecimals = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : false; if (forceKeepTwoDecimals || baseScale > 1) { return Math.round(value * 100) / 100; } return Math.round(value); } /** 无原生桥时按屏宽推算 scale(含平板与 375 基准窄屏区间) */ function getScaleByViewport() { if (!_canusedom.canUseDom) return 1; var deviceWidth = window.innerWidth; if (!deviceWidth) return 1; if (deviceWidth >= 600) { return 1.2; } if (deviceWidth >= 375 && deviceWidth < 600) { var ratio = deviceWidth / 375; return ratio >= 1.17 ? 1.17 : ratio; } return 1; } /** 通过 jmfe.callNative 拉取 DongScreenAdapterPlugin;失败返回 null */ function getScaleByNative() { return (0, _async_to_generator._)(function() { var _window_jmfe, _res_data, res, parsed, e; return (0, _ts_generator._)(this, function(_state) { switch(_state.label){ case 0: if (!_canusedom.canUseDom || !((_window_jmfe = window.jmfe) === null || _window_jmfe === void 0 ? void 0 : _window_jmfe.callNative)) return [ 2, null ]; _state.label = 1; case 1: _state.trys.push([ 1, 3, , 4 ]); return [ 4, window.jmfe.callNative('DongScreenAdapterPlugin', 'getScale', JSON.stringify({}), '') ]; case 2: res = _state.sent(); if ((res === null || res === void 0 ? void 0 : res.status) === '0' && ((_res_data = res.data) === null || _res_data === void 0 ? void 0 : _res_data.scale) !== undefined) { parsed = Number(res.data.scale); if (Number.isFinite(parsed) && parsed > 0) { return [ 2, parsed ]; } } return [ 3, 4 ]; case 3: e = _state.sent(); return [ 3, 4 ]; case 4: return [ 2, null ]; } }); })(); } /** 统一获取缩放:站内原生优先,失败则用视口规则 */ function getScaleF() { return (0, _async_to_generator._)(function() { var nativeScale; return (0, _ts_generator._)(this, function(_state) { switch(_state.label){ case 0: return [ 4, getScaleByNative() ]; case 1: nativeScale = _state.sent(); if (nativeScale) return [ 2, nativeScale ]; return [ 2, getScaleByViewport() ]; } }); })(); } /** 校验后更新内存中的 scale,并写入 --nut-scale-f */ function setScaleF(nextScale) { var validScale = Number.isFinite(nextScale) && nextScale > 0 ? nextScale : 1; scale = validScale; applyScaleCssVars(validScale); return scale; } /** 重新拉取缩放;可选同时切换 profile,避免与当前值相同时重复写 DOM */ function refreshScaleF(nextProfile) { return (0, _async_to_generator._)(function() { var nextScale; return (0, _ts_generator._)(this, function(_state) { switch(_state.label){ case 0: if (nextProfile) { setScaleProfile(nextProfile); } return [ 4, getScaleF() ]; case 1: nextScale = _state.sent(); if (!scale || nextScale !== scale) { setScaleF(nextScale); } return [ 2, scale ]; } }); })(); } function initScaleF(nextProfile) { if (!_canusedom.canUseDom) return function() {}; setScaleProfile(nextProfile); var handler = function handler() { refreshScaleF(); }; handler(); window.addEventListener('resize', handler); return function() { window.removeEventListener('resize', handler); }; } /** 更新全局 profile,并在当前 scale 下重刷 CSS 变量 */ function setScaleProfile(nextProfile) { profile = normalizeProfile(nextProfile); // profile 切换后需要重新应用当前缩放值。 setScaleF(scale); return profile; } function calcByProfile(baseValue) { var options = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : {}; var _options_profile; var currentProfile = normalizeProfile((_options_profile = options.profile) !== null && _options_profile !== void 0 ? _options_profile : profile); var _options_scene; var scene = (_options_scene = options.scene) !== null && _options_scene !== void 0 ? _options_scene : 'layout'; var currentScale = Number.isFinite(options.scale) && Number(options.scale) > 0 ? Number(options.scale) : scale; var _options_device; var device = (_options_device = options.device) !== null && _options_device !== void 0 ? _options_device : getCurrentDevice(); var ratio = getSceneRatio(scene, currentProfile); var rawValue = baseValue * ratio * currentScale; var forceKeepTwoDecimals = scene === 'font' && currentProfile === 'large' && device === 'pad'; return roundByScaleRule(rawValue, currentScale, forceKeepTwoDecimals); }