Vue3 驾驶舱屏幕适配实战

Vue3 驾驶舱屏幕适配实战

在驾驶舱、大屏可视化、数据看板项目中,屏幕适配一直是高频问题。

本文分享一个我在实际项目中使用的方案:

Vue3 + transform scale 缩放 + 防抖优化 + 组件封装

最终实现:

  • 多分辨率自适应

  • 页面始终完整显示

  • 自动居中

  • 缩放流畅不卡顿

  • 可直接复用到多个驾驶舱项目


一、适配思路

设计稿尺寸固定:

1920 × 1080

页面开发阶段完全按照设计稿编写。

运行时,根据当前浏览器窗口尺寸计算缩放比例:

当前宽度 / 1920
当前高度 / 1080

取两者最小值:

scale = min(widthScale, heightScale)

这样可以保证:

  • 页面内容完整显示

  • 不会裁切

  • 保持原始比例


二、组件完整代码(ScaleBox.vue)

<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue'

const width = 1920
const height = 1080

const scaleBox = ref(null)

let resizeHandler = null
let resizeEndTimer = null

// 计算缩放比例
const getScale = () => {
  const ww = window.innerWidth / width
  const wh = window.innerHeight / height
  return Number(Math.min(ww, wh).toFixed(4))
}

// 设置缩放
const setScale = () => {
  const el = scaleBox.value
  if (!el) return

  const scale = getScale()

  el.classList.add('no-transition')

  el.style.setProperty('--scale', scale)

  clearTimeout(resizeEndTimer)

  resizeEndTimer = setTimeout(() => {
    el.classList.remove('no-transition')
  }, 180)
}

// 防抖函数
const debounce = (fn, delay = 100) => {
  let timer = null

  return () => {
    if (timer) clearTimeout(timer)

    timer = setTimeout(() => {
      fn()
    }, delay)
  }
}

onMounted(() => {
  setScale()

  resizeHandler = debounce(setScale, 50)

  window.addEventListener('resize', resizeHandler)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', resizeHandler)
})
</script>

<template>
  <div
    ref="scaleBox"
    class="ScaleBox"
    :style="{
      width: `${width}px`,
      height: `${height}px`
    }"
  >
    <slot></slot>
  </div>
</template>

<style>
.ScaleBox {
  --scale: 1;

  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 999;

  display: flex;
  flex-direction: column;

  transform: scale(var(--scale)) translate(-50%, -50%);
  transform-origin: 0 0;

  transition: transform 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);

  will-change: transform;
}

.no-transition {
  transition: none !important;
}
</style>

三、核心代码解析

1. 为什么取最小值缩放?

Math.min(ww, wh)

例如:

屏幕尺寸:

1600 × 900

计算:

1600 / 1920 = 0.833
900 / 1080 = 0.833

缩放比例:

0.833

如果屏幕是超宽屏:

2560 × 1080

计算:

2560 / 1920 = 1.333
1080 / 1080 = 1

最终取:

1

这样页面完整显示,只会左右留白,不会裁切内容。


2. 为什么居中?

top: 50%;
left: 50%;
transform: scale(...) translate(-50%, -50%);

作用:

无论屏幕大小如何变化,页面始终居中显示。

非常适合驾驶舱场景。


3. 为什么 resize 要防抖?

拖动浏览器窗口时,会频繁触发:

resize

如果每次都重新计算缩放,会造成:

  • 卡顿

  • 抖动

  • 性能下降

所以加入防抖:

debounce(setScale, 50)

50ms 内只执行一次。


4. 为什么临时关闭动画?

缩放变化过程中,如果保留 transition,会出现拖动窗口时动画抖动。

所以:

el.classList.add('no-transition')

缩放结束后再恢复:

180ms 后移除

这样体验更丝滑。


四、使用方式

在页面最外层包裹:

<ScaleBox>
  <Dashboard />
</ScaleBox>

然后内部所有内容仍按:

1920 × 1080

开发即可,无需关心不同屏幕尺寸。值得注意的是,开发阶段最好使用 1920 × 1080 分辨率屏幕,或者至少使用 16:9 比例屏幕 进行开发与调试。


五、优点分析

完全按设计稿开发,无需频繁换算单位,并且封装成组件后,新项目直接复制即可使用。

驾驶舱大屏适配方案总结 2026-04-14
驾驶舱适配进阶:解决超宽屏留白问题 2026-04-16

评论区