vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > vue适配屏幕分辨率,以及屏幕的缩放

vue适配屏幕分辨率,以及屏幕的缩放方式

作者:weixin_54820790

这篇文章主要介绍了vue适配屏幕分辨率,以及屏幕的缩放方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

vue适配屏幕分辨率以及屏幕的缩放

utils新建一个文件devicePixelRatio.js

class DisplayAdapter {
    constructor(options = {}) {
        this.options = {
            designWidth: 1920,       // 设计稿基准宽度
            baseFontSize: 16,        // 基础字体大小
            maxScale: 2,             // 最大缩放比例
            useTransform: true,      // 使用transform缩放
            debounceTime: 100,       // 防抖时间
            ...options
        };

        this.lastDPR = window.devicePixelRatio;
        this.init();
    }

    // 系统检测(增强版)
    _getSystem () {
        const agent = navigator.userAgent.toLowerCase();
        const isWindows = /windows/.test(agent);
        const isHighDPI = window.devicePixelRatio >= 1.25;
        return isWindows && isHighDPI;
    }

    // 防抖函数
    _debounce (fn) {
        let timer;
        return (...args) => {
            clearTimeout(timer);
            timer = setTimeout(() => fn.apply(this, args), this.options.debounceTime);
        };
    }

    // 动态REM计算
    _setRem () {
        const clientWidth = document.documentElement.clientWidth;
        const scale = Math.min(clientWidth / this.options.designWidth, this.options.maxScale);
        document.documentElement.style.fontSize =
            `${this.options.baseFontSize * scale}px`;
    }

    // DPI缩放校正
    _correctDPR () {
        const currentDPR = window.devicePixelRatio;
        if (Math.abs(currentDPR - this.lastDPR) > 0.05) {
            this.lastDPR = currentDPR;

            if (this.options.useTransform) {
                const scale = 1 / currentDPR;
                document.body.style.transform = `scale(${scale})`;
                document.body.style.transformOrigin = 'top left';
                document.body.style.width = `${this.options.designWidth / scale}px`;
            } else {
                document.body.style.zoom = 1 / currentDPR;
            }
        }
    }

    // 组合适配方法
    _adaptLayout () {
        this._correctDPR();
        this._setRem();
    }

    // 事件监听
    _watch () {
        const debouncedAdapt = this._debounce(() => this._adaptLayout());
        const events = ['resize', 'pageshow', 'orientationchange'];

        events.forEach(event => {
            window.addEventListener(event, debouncedAdapt);
        });

        // 监听DPI变化(仅现代浏览器)
        if (window.matchMedia) {
            window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`)
                .addEventListener('change', debouncedAdapt);
        }
    }

    // 初始化样式
    _injectBaseStyles () {
        const style = document.createElement('style');
        style.textContent = `
        html {
          overflow: hidden;
          width: 100vw;
          height: 100vh;
        }
        body {
          position: relative;
          margin: 0;
          padding: 0;
          overflow: hidden;
          transform-origin: top left;
        }
      `;
        document.head.appendChild(style);
    }

    // 初始化
    init () {
        if (this._getSystem()) {
            this._injectBaseStyles();
            this._adaptLayout();
            this._watch();
        } else {
            // 非Windows系统仅启用REM适配
            this._setRem();
            window.addEventListener('resize', this._debounce(() => this._setRem()));
        }
    }
}

// 初始化配置
new DisplayAdapter({
    designWidth: 1920,
    useTransform: true,
    maxScale: 1.5
});

export default DisplayAdapter;

在app.vue里面使用

import DevicePixelRatio from "@/utils/devicePixelRatio"

 created () {
    new DevicePixelRatio().init()
}

utils里面再新建一个rem.js

// rem等比适配配置文件
// 基准大小
const baseSize = 16;
// 设置 rem 函数
function setRem () {
    // 当前页面宽度相对于 1920宽的缩放比例,可根据自己需要修改。
    const scale = document.documentElement.clientWidth / 1920;
    // 设置页面根节点字体大小(“Math.min(scale, 2)” 指最高放大比例为2,可根据实际业务需求调整)
    if (document.documentElement.clientWidth >= 2560) {
        document.documentElement.style.fontSize =
            baseSize * Math.min(scale, 2) + "px";
    } else {
        document.documentElement.style.fontSize =
            baseSize * Math.min(scale, 1) + "px";
    }

}
// 初始化
setRem();
// 改变窗口大小时重新设置 rem
// window.onresize = function () {
//     setRem();
// };
window.addEventListener('resize', function () {
    setRem();
});

main.js中引用

import rem from "@/utils/rem";

vue.config.js里面修改

 // 引入等比适配插件
const px2rem = require('postcss-px2rem');

// 配置基本大小
const postcss = px2rem({
    // 基准大小 baseSize,需要和rem.js中相同
    remUnit: 16,
});
 
// 配置基本大小
const postcss = px2rem({
  // 基准大小 baseSize,需要和rem.js中相同
  // remUnit: 14 代表 1rem = 14px; 所以当你一个14px值时,它会自动转成 (14px/14)rem
  remUnit: 14
})
 
// 使用等比适配插件
module.exports = {
  lintOnSave: true,
  css: {
        loaderOptions: {
            scss: {
                additionalData: `@import "./src/assets/styles/module.scss";`,
                sassOptions: { outputStyle: "expanded" },
            },
            postcss: {
                plugins: [
                    postcss,
                ],
            },
        },
    },
}

与vue.config.js同根目录下创建postcss.config.js

// module.exports = {
//     plugins: {
//         'postcss-px-to-viewport': {
//             // 设计稿宽度是电脑屏幕宽度

//             unitToConvert: 'px',  // 需要转换的单位,默认为"px"
//             viewportWidth: 1920, //  设计稿的视口宽度
//             unitPrecision: 5, // 单位转换后保留的精度
//             propList: ['*'], // 能转化为vw的属性列表
//             viewportUnit: 'vw', //  希望使用的视口单位
//             fontViewportUnit: 'vw', // 字体使用的视口单位
//             selectorBlackList: [], // 需要忽略的CSS选择器
//             minPixelValue: 1, // 最小的转换数值,如果为1的话,只有大于1的值会被转换
//             mediaQuery: false, // 媒体查询里的单位是否需要转换单位
//             replace: true, // 是否直接更换属性值,而不添加备用属性
//             exclude: [], // 忽略某些文件夹下的文件或特定文件
//             include: undefined,  // 如果设置了include,那将只有匹配到的文件才会被转换,例如只转换 'src/mobile' 下的文件 (include: /\/src\/mobile\//)
//             landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
//             landscapeUnit: 'vw' // 横屏时使用的单位
//         },
//     },
// };
// module.exports = () => ({
//     plugins: [
//         require("autoprefixer")(),
//         // require("postcss-px2rem")({ remUnit: 75 })
//         require("postcss-pxtorem")({
//             rootValue: 16,//结果为:设计稿元素尺寸/16,比如元素宽320px,最终页面会换算成 20rem
//             propList: ["*"]
//         })
//     ]
// })

//另一种可以新建postcss.config.js,写入如下代码
module.exports = {
    plugins: {
        // 兼容浏览器,添加前缀
        autoprefixer: {
            overrideBrowserslist: [
                "Android 4.1",
                "iOS 7.1",
                "Chrome > 31",
                "ff > 31",
                "ie >= 8",
                "last 10 versions", // 所有主流浏览器最近10版本用
            ],
            grid: true,
        },
        "postcss-px2rem": {
            rootValue: 16, //结果为:设计稿元素尺寸/16,比如元素宽320px,最终页面会换算成 20rem
            propList: ["*"], //是一个存储哪些将被转换的属性列表,这里设置为['*']全部,假设需要仅对边框进行设置,可以写['*', '!border*']
            unitPrecision: 5, //保留rem小数点多少位
            //selectorBlackList: ['.radius'],  //则是一个对css选择器进行过滤的数组,比如你设置为['fs'],那例如fs-xl类名,里面有关px的样式将不被转换,这里也支持正则写法。
            replace: true, //这个真不知到干嘛用的。有知道的告诉我一下
            mediaQuery: false, //媒体查询( @media screen 之类的)中不生效
            minPixelValue: 12, //px小于12的不会被转换
        },
    },
};

  // 蓝湖上设计稿自定义为375px 测量值直接写入即可 若设计稿为750px 则rootValue: 32

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文