react ant-design通用页面自适应适配不同分辨率屏幕的方法工具类
该方法会根据 目标分辨率(options.width/height) 和 当前窗口尺寸(innerWidth/innerHeight) 计算缩放比例,并保持 等比例缩放(Math.min(scaleX, scaleY)
),确保内容不变形:
/*** 防抖函数* @param {Function} fn - 需要防抖的函数* @param {number} delay - 延迟时间(ms)* @returns {Function} 防抖后的函数*/
function debounce(fn, delay) {let timer = null;return function (...args) {if (timer) clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);};
}/*** 带滚动条支持的自适应缩放* @param {string|HTMLElement} target - 目标元素* @param {Object} config - 配置项* @param {number} config.designWidth - 设计稿宽度(如1920)* @param {number} config.designHeight - 设计稿总高度(如1080)* @param {number} [config.topOffset=60] - 顶部固定高度(如导航栏)* @param {boolean} [config.scrollable=true] - 是否启用垂直滚动*/
export function scrollableAutoScale(target, config) {const el = typeof target === 'string' ? document.querySelector(target) : target;if (!el) return () => { };const {designWidth = 1920,designHeight = 1080,topOffset1 = 0,topOffset2 = 0,scrollable = true} = config;// 1. 设备像素比检测和优化const dpr = window.devicePixelRatio || 1;const isRetina = dpr >= 1.5;const scalePrecision = isRetina ? 1000 : 400; // 视网膜屏使用更高精度// 2. 高清渲染样式优化Object.assign(el.style, {willChange: 'transform',backfaceVisibility: 'hidden',transformStyle: 'preserve-3d',textRendering: isRetina ? 'geometricPrecision' : 'optimizeLegibility',WebkitFontSmoothing: isRetina ? 'subpixel-antialiased' : 'antialiased',imageRendering: isRetina ? 'crisp-edges' : 'auto'});// 3. 创建外层容器(添加过渡效果、增加视网膜屏优化)const container = document.createElement('div');Object.assign(container.style, {position: 'fixed',top: `${topOffset2}px`,left: '0',width: '100vw',height: `calc(100vh - ${topOffset1 + topOffset2}px)`,overflow: 'hidden', // 默认隐藏,后面动态调整margin: '0',padding: '0',zIndex: '1',// 背景图优化backgroundImage: getComputedStyle(el).backgroundImage,backgroundPosition: getComputedStyle(el).backgroundPosition,backgroundRepeat: getComputedStyle(el).backgroundRepeat,backgroundSize: getComputedStyle(el).backgroundSize,imageRendering: isRetina ? 'crisp-edges' : 'auto',// 平滑过渡 滚动条出现/消失transition: 'overflow 0.2s ease-out'});el.style.backgroundImage = 'none';el.parentNode.insertBefore(container, el);container.appendChild(el);// 4. 目标元素样式(使用3D变换)Object.assign(el.style, {position: 'absolute',transformOrigin: 'top left',width: `${designWidth}px`,left: '0',right: '0',transformStyle: 'preserve-3d'});// 5. 增强版缩放计算let lastScale = 0;const calculate = () => {const viewportWidth = container.clientWidth;const viewportHeight = container.clientHeight;// 高精度缩放计算const rawScale = viewportWidth / designWidth;const scale = Math.round(rawScale * scalePrecision) / scalePrecision;const contentHeight = designHeight * scale;// 动态阈值(视网膜屏使用更敏感的阈值)const scaleThreshold = isRetina ? 0.001 : 0.0025;if (Math.abs(scale - lastScale) > scaleThreshold) {// 使用scale3d提升渲染质量el.style.transform = `scale3d(${scale}, ${scale}, 1)`;// 垂直居中优化if (!scrollable) {el.style.transform = `scale3d(${scale}, ${scale}, 1) translate3d(0, ${(viewportHeight - contentHeight) / 2}px, 0)`;}lastScale = scale;}// 滚动条缓冲(视网膜屏增加缓冲)const scrollBuffer = isRetina ? 5 : 2;container.style.overflowY = scrollable && (contentHeight > viewportHeight + scrollBuffer)? 'auto': 'hidden';};// 6. 高性能监听(双RAF防抖)使用requestAnimationFrame优化监听频率,避免高频触发计算导致性能问题。let rafId = null;const optimizedCalculate = () => {if (rafId) cancelAnimationFrame(rafId);rafId = requestAnimationFrame(() => {calculate();rafId = requestAnimationFrame(() => {calculate(); // 双RAF确保布局稳定rafId = null;});});};const observer = new ResizeObserver(debounce(optimizedCalculate, isRetina ? 30 : 50));observer.observe(container);// 7. 三重初始化保障requestAnimationFrame(() => {calculate();setTimeout(() => {requestAnimationFrame(calculate);}, 200);});return () => {observer.disconnect();if (rafId) cancelAnimationFrame(rafId);container.parentNode?.insertBefore(el, container);container.parentNode?.removeChild(container);};
}
react页面中的调用:
import React, { useEffect, useRef } from 'react';
import { optimizedAutoScale } from '../utils/optimizedAutoScale';const Index = () => {const containerRef = useRef(null);useEffect(() => {if (!containerRef.current) return;const destroy = scrollableAutoScale(containerRef.current, {designWidth: 1920,minHeight: 1080, // 设计稿总高度topOffset1: 53, // 动态获取顶部高度topOffset2: 42, // 动态获取顶部高度scrollable: true, // 允许滚动});return () => {destroy();};}, []);return (<div ref={containerRef}>{/* 动态内容区域,高度会自动计算 */}</div>);
};export default Index;