📚 《vfit.js大屏适配指南》系列
第1篇:拒绝rem计算!Vue3大屏适配,我是这样做的
第2篇:还在用rem做大屏适配?用vfit.js一键搞定,告别改稿8版的噩梦
第3篇:别再抄网上的Scale缩放代码了!50行源码教你写一个永不翻车的大屏适配
第4篇:大屏元素永远对不齐?一招搞定所有绝对定位,再也不用调像素到凌晨
90%的大屏开发者,都在网上抄过这段"万能缩放代码":
window.addEventListener('resize', () => {
const scale = window.innerWidth / 1920
document.body.style.transform = `scale(${scale})`
})
我也抄了3年,直到上个月做政务大屏,客户把大屏嵌进了iframe里——整个页面直接缩成了一团。 改了3天没搞定,直到扒开vfit的源码才发现:原来我们手写的Scale,从根上就错了。 今天把这50行核心源码拆解给你,看完你再也不用抄任何人的代码。
一、手写Scale的3个必死场景,你一定踩过
别以为你的代码现在能用,只要遇到下面任意一个场景,立刻翻车:
- iframe嵌套:窗口大小没变,容器大小变了,你的缩放代码完全没反应
- 微前端:大屏作为子应用嵌入主系统,坐标和缩放全部错乱
- 弹窗内大屏:点击按钮弹出一个大屏弹窗,打开就是变形的
这些问题的根源只有一个:你监听的是window.resize,而不是大屏容器本身的大小变化。
二、第一斧:抛弃window.resize,拥抱ResizeObserver
这是vfit和所有手写Scale最本质的区别。
window.resize只能监听整个浏览器窗口的大小变化,而ResizeObserver可以监听任意DOM元素的尺寸变化。
核心代码:
// 创建一个观察者
const observer = new ResizeObserver((entries) => {
// 拿到容器的实际宽高
const { width, height } = entries[0].contentRect
// 计算正确的缩放比例
const scale = calculateScale(width, height)
// 应用缩放
applyScale(container, scale)
})
// 监听大屏容器,而不是window
observer.observe(document.querySelector('#app'))
就这几行代码,直接解决了iframe、微前端、弹窗内大屏的所有适配问题。 不管你的大屏放在哪里,只要它的容器尺寸变了,就会自动触发缩放。
三、第二斧:一行公式,搞定所有比例计算
很多人写Scale,比例计算都是错的,这就是为什么你的大屏会变形。 错误写法:
// 只按宽度缩放,高度会被拉伸,圆形变椭圆
const scale = width / designWidth
正确写法(vfit同款):
// auto模式:比较容器和设计稿的宽高比,谁更"瘦"听谁的
const calculateScale = (containerWidth, containerHeight, designWidth, designHeight) => {
return containerWidth / containerHeight < designWidth / designHeight
? containerWidth / designWidth
: containerHeight / designHeight
}
这个公式的神奇之处在于:
- 1920×1080的设计稿,放到3840×2160的4K屏,自动按2倍缩放
- 放到16:10的带鱼屏,自动留出上下黑边,绝不裁切,绝不变形
- 放到iPad竖屏,自动留出左右黑边,所有元素比例完全一致
四、第三斧:GPU硬件加速拉满,告别卡顿
很多人大屏做出来卡成PPT,就是因为用了错误的CSS属性。 vfit只用了一行CSS,性能直接拉满:
const applyScale = (el, scale) => {
// 用transform: scale,调用GPU硬件加速
el.style.transform = `scale(${scale})`
// 原点设为左上角,保证定位准确
el.style.transformOrigin = 'left top'
// 自动居中
el.style.marginLeft = `${(window.innerWidth - el.offsetWidth * scale) / 2}px`
el.style.marginTop = `${(window.innerHeight - el.offsetHeight * scale) / 2}px`
}
不用百分比,不用rem,直接操作GPU。 内部的ECharts、高德地图、Three.js完全感觉不到外面的变化,60帧丝滑运行。
五、终极福利:50行完整源码,直接复制用
把上面的代码整合起来,就是一个完整的、永不翻车的大屏适配工具:
export const createScale = (options) => {
const { target, designWidth = 1920, designHeight = 1080 } = options
const container = document.querySelector(target)
if (!container) return
const calculateScale = (w, h) => {
return w / h < designWidth / designHeight ? w / designWidth : h / designHeight
}
const applyScale = (scale) => {
container.style.transform = `scale(${scale})`
container.style.transformOrigin = 'left top'
container.style.marginLeft = `${(window.innerWidth - designWidth * scale) / 2}px`
container.style.marginTop = `${(window.innerHeight - designHeight * scale) / 2}px`
}
const observer = new ResizeObserver((entries) => {
const { width, height } = entries[0].contentRect
applyScale(calculateScale(width, height))
})
observer.observe(container)
// 初始化
applyScale(calculateScale(window.innerWidth, window.innerHeight))
return { destroy: () => observer.disconnect() }
}
// 使用方法
createScale({ target: '#app', designWidth: 1920, designHeight: 1080 })
六、如果你不想自己写,直接用vfit.js
上面的源码就是vfit的核心逻辑,vfit在此基础上做了更多优化:
- 支持多种缩放模式(auto、width、height、contain、cover)
- 内置防抖,避免频繁触发缩放
- 提供FitContainer组件,解决绝对定位跑偏问题
- 零依赖,打包后只有2KB
一行代码搞定所有适配:
npm install vfit
import { createApp } from 'vue'
import { createFitScale } from 'vfit'
import 'vfit/style.css'
createApp(App)
.use(createFitScale({ designWidth: 1920, designHeight: 1080 }))
.mount('#app')
💬 互动福利
你抄的Scale代码翻过哪些车?是iframe嵌套失效,还是微前端错乱? 评论区晒出你的血泪史,抽3人送手写Scale终极版源码+大屏常见分辨率适配速查表。
评论+点赞+收藏,私信【大屏源码】,立即领取10套政务大屏经典布局模板。
官方资源直达:
vfit.js 官网:vfit.raychart.cn/
GitHub 仓库:github.com/v-plugin/vf…
下一篇预告:大屏元素永远对不齐?一招搞定所有绝对定位,再也不用调像素到凌晨。