vue3+ts+vite数据大屏自适应总结(两种方法)

总结一下我常用的数据大屏自适应方法

目录

1、通过css缩放方案: 利用transform:scale 进行适配

我一般使用 v-scale-screen 插件

主要用于同比例缩放,例如16:9(1k,2k,4k)

vue2版本(npm官网):https://www.npmjs.com/package/vue2-scale-box

vue3版本(npm官网):https://www.npmjs.com/package/vue3-scale-box

typescript 复制代码
yarn add vue3-scale-box

<template>
  <ScaleBox
    :width="1920"
    :height="1080"
    bgc="transparent"
    :delay="100"
    :isFlat="false"
  >
    <div class="ec-demo" id="ec-demo"></div>
  </ScaleBox>
</template>
<script setup>
import ScaleBox from "vue3-scale-box";
</script>

2、采用rem布局, 根据屏幕分辨率大小不同,调整根元素html的font-size, 从而达到每个元素宽高自动变化,适配不同屏幕

我一般使用 postcss-pxtorem + lib-flexible 插件

主要用于多个不同比例缩放,例如16:9(1k,2k,4k),21:9或其他比例

适配的方法总体分为两步:

  1. px转换成rem
  2. rem根据屏幕大小重置基数改变大小

2.1、先下载postcss-pxtorem

typescript 复制代码
yarn add postcss-pxtorem 

"postcss-pxtorem": "^6.0.0",

2.2、在vite.config.ts配置

typescript 复制代码
import postcssPxtoRem from "postcss-pxtorem";

css: {
  postcss: {
    plugins: [
      postcssPxtoRem({
        rootValue: 192, // 按照自己的设计稿修改 1920/10
        unitPrecision: 5, // 保留到5位小数
        selectorBlackList: ["ignore"], // 忽略转换正则匹配项
        propList: ["*", "!border"],
        replace: true,
        mediaQuery: false, // 媒体查询( @media screen 之类的)中不生效
        minPixelValue: 1, //可以选择px小于1的不会被转换
      }),
    ],
  },
},

2.3、在src/utils下创建flexible.js文件(lib-flexible插件建议放到本地)

因为我要适配不同比例的大屏,我把lib-flexible插件放在了本地(方便修改)

可以在 refreshRem() 方法中对不同分辨率进行设置

typescript 复制代码
(function (win, lib) {
  var doc = win.document;
  var docEl = doc.documentElement;
  var metaEl = doc.querySelector('meta[name="viewport"]');
  var flexibleEl = doc.querySelector('meta[name="flexible"]');
  var dpr = 0;
  var scale = 0;
  var tid;
  var flexible = lib.flexible || (lib.flexible = {});

  if (metaEl) {
    console.warn("将根据已有的meta标签来设置缩放比例");
    var match = metaEl
      .getAttribute("content")
      .match(/initial\-scale=([\d\.]+)/);
    if (match) {
      scale = parseFloat(match[1]);
      dpr = parseInt(1 / scale);
    }
  } else if (flexibleEl) {
    var content = flexibleEl.getAttribute("content");
    if (content) {
      var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
      var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
      if (initialDpr) {
        dpr = parseFloat(initialDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
      if (maximumDpr) {
        dpr = parseFloat(maximumDpr[1]);
        scale = parseFloat((1 / dpr).toFixed(2));
      }
    }
  }

  if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone || isAndroid) {
      // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
      if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
        dpr = 3;
      } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
        dpr = 2;
      } else {
        dpr = 1;
      }
    } else {
      // 其他设备下,仍旧使用1倍的方案
      dpr = devicePixelRatio;
    }
    scale = 1 / dpr;
    // scale = 1 * dpr;
  }

  docEl.setAttribute("data-dpr", dpr);
  if (!metaEl) {
    metaEl = doc.createElement("meta");
    metaEl.setAttribute("name", "viewport");
    metaEl.setAttribute(
      "content",
      "initial-scale=" +
        scale +
        ", maximum-scale=" +
        scale +
        ", minimum-scale=" +
        scale +
        ", user-scalable=no"
    );
    if (docEl.firstElementChild) {
      docEl.firstElementChild.appendChild(metaEl);
    } else {
      var wrap = doc.createElement("div");
      wrap.appendChild(metaEl);
      doc.write(wrap.innerHTML);
    }
  }

  function refreshRem() {
    var width = docEl.getBoundingClientRect().width;
    var height = docEl.getBoundingClientRect().height;

    if (width / dpr < 1600) {
      width = 1920 * dpr;
    }
    var rem = (width * dpr) / 10;
    docEl.style.fontSize = rem + "px";
    flexible.rem = win.rem = rem;
    // if(width>3040&&width<3640){
    //   docEl.style.fontSize = 1 + "px";
    //   flexible.rem = 1 + "px";
    // }
  }
  win.addEventListener(
    "resize",
    function () {
      refreshRem();
    },
    false
  );
  win.addEventListener(
    "pageshow",
    function (e) {
      if (e.persisted) {
        refreshRem();
      }
    },
    false
  );

  if (doc.readyState === "complete") {
    doc.body.style.fontSize = 12 * dpr + "px";
  } else {
    doc.addEventListener(
      "DOMContentLoaded",
      function () {
        doc.body.style.fontSize = 12 * dpr + "px";
      },
      false
    );
  }

  refreshRem();

  flexible.dpr = win.dpr = dpr;
  flexible.refreshRem = refreshRem;
  flexible.rem2px = function (d) {
    var val = parseFloat(d) * this.rem;
    if (typeof d === "string" && d.match(/rem$/)) {
      val += "px";
    }
    return val;
  };
  flexible.px2rem = function (d) {
    var val = parseFloat(d) / this.rem;
    if (typeof d === "string" && d.match(/px$/)) {
      val += "rem";
    }
    return val;
  };
})(window, window["lib"] || (window["lib"] = {}));

2.4、在main.js中引入flexible.js

typescript 复制代码
//px转rem
// 使用下面@ts-ignore表示忽略ts类型检测,否则下面代码打包时会报错
import '@/utils/flexible.js'

2.5、注意事项

1、 框架组件和标签中直接定义的 width和height进行不了转换, 例如img标签

2、 大多框架只适配1920*1080的,其他比例,框架组件可能会变形,需要单独设置,可以在全局css文件进行修改。

相关推荐
GISer_Jing2 小时前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪3 小时前
CSS复习
前端·css
咖啡の猫5 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲7 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5818 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路8 小时前
GeoTools 读取影像元数据
前端
ssshooter9 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry9 小时前
Jetpack Compose 中的状态
前端
dae bal10 小时前
关于RSA和AES加密
前端·vue.js
柳杉10 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化