首页 分享 vue3 + ts + vite 移动端适配

vue3 + ts + vite 移动端适配

来源:花匠小妙招 时间:2024-12-07 18:39

本文章使用 Vant UI 框架,其他 UI 框架可自行切换

本文章最终推荐方案为:postcss-px-to-viewport-8-plugin + 自定义行内样式转换插件

像素单位:px、em、rem、vw/vh等的区别?

px:是像素单位。它是代表显示器上每一个显示的像素点,根据用户屏幕显示器的分辨率决定em:为相对单位,相对于当前元素内文本的字体尺寸。如果当前元素没有指定字体尺寸,那么以浏览器默认的字体尺寸为准。例如,当前元素设置了字体尺寸为24px,那么2em就代表48px

rem:为相对单位,相对于<HTML>元素文本的字体尺寸。如果<HTML>元素没有指定字体尺寸,那么以浏览器默认的字体尺寸为准

例如,<HTML>元素设置了字体尺寸为24px,那么2rem就代表48px

vwvh:相对单位,相对于当前视口(),又叫 Viewport 

例如,10vw代表当前视口宽度的10%,20vh代表当前视口高度的20%

%:相对单位,相对于父元素的相关尺寸

例如,父元素设置了height: 100px,那么它的子元素height: 50%就代表50px

总结:一般移动端适配,使用 rem布局 或 Viewport (vw/vh)

rem 布局

如果需要使用 rem 单位进行适配,常常使用postcss-pxtorem 或 lib-flexible 两个方案

postcss-pxtorem 是一款 PostCSS 插件,用于将 px 单位转化为 rem 单位

postcss-pxtorem 已有4年没有更新,因此它是不支持 PostCSS 8.0+ 版本的(PostCss 8.0+ 以上的版本是主流,也是未来的方向),因此不推荐使用该方案

lib-flexible 用于设置 rem 基准值

访问 lib-flexible 的github仓库,文档中有这么一段话

由于viewport单位得到众多浏览器的兼容,lib-flexible这个过渡方案已经可以放弃使用,不管是现在的版本还是以前的版本,都存有一定的问题。建议大家开始使用viewport来替代此方。

因此不推荐使用该方案

Viewport布局

Vant 默认使用 px 作为样式单位(很多UI框架都是默认px),如果需要使用 viewport 单位 (vw, vh, vmin, vmax),推荐使用 postcss-px-to-viewport 进行转换。

postcss-px-to-viewport 是一款 PostCSS 插件,用于将 px 单位转化为 vw/vh 单位。

postcss-px-to-viewport 不适配postcss 8.0+ 最新版本的, 已弃用,目前有基于postcss 8 8.0+的插件:postcss-px-to-viewport-8-plugin

安装插件

npm install postcss postcss-loader postcss-px-to-viewport-8-plugin -D

配置 vite.config.ts

import { defineConfig, loadEnv } from "vite";

import vue from "@vitejs/plugin-vue";

import AutoImport from "unplugin-auto-import/vite";

import Components from "unplugin-vue-components/vite";

import { VantResolver } from "@vant/auto-import-resolver";

import path from "path";

import postcsspxtoviewport8plugin from "postcss-px-to-viewport-8-plugin";

export default defineConfig(({ command, mode }) => {

const env = loadEnv(mode, process.cwd(), "VITE_");

console.log(env);

const port: number = (env.VITE_APP_PORT as any) || 80;

return {

base: env.VITE_APP_CONTEXT_PATH,

plugins: [

vue(),

AutoImport({

imports: ["vue", "vue-router"],

dts: "src/auto-import.d.ts",

}),

Components({

dts: "src/components.d.ts",

resolvers: [VantResolver()],

}),

],

resolve: {

alias: {

"@": path.resolve("./src"),

},

},

server: {

host: true,

port: Number(port),

open: true,

proxy: {

[env.VITE_APP_BASE_API]: {

target: env.VITE_PROXY_TARGET_URL,

changeOrigin: true,

rewrite: (path) =>

path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),

},

},

},

css: {

postcss: {

plugins: [

postcsspxtoviewport8plugin({

unitToConvert: "px",

viewportWidth: 375,

unitPrecision: 5,

propList: ["*"],

viewportUnit: "vw",

fontViewportUnit: "vw",

selectorBlackList: [],

minPixelValue: 1,

mediaQuery: true,

replace: true,

exclude: [/node_modules/],

include: [],

landscape: false,

landscapeUnit: "vw",

landscapeWidth: 1024,

}),

],

},

},

};

案例:

<template>

<!-- 适配生效 -->

<div class="div1">div1</div>

<!-- 适配不生效:写在style里面的则不能转换,插件不支持这种方式 -->

<div style="width: 185px; height: 50px; background-color: blue">div2</div>

</template>

<script setup lang="ts"></script>

<style>

.div1 {

width: 185px;

height: 50px;

background-color: red;

}

</style>

虽然postcss-px-to-viewport-8-plugin做适配,但是行内样式不能转换为vw,所以我们自定义个插件,将内样式px转成vw

创建文件 src/plugin/vite-plugin-style-vw-loader.ts, 内容为:

interface IdefaultsProp {

unitToConvert: string;

viewportWidth: number;

unitPrecision: number;

viewportUnit: string;

fontViewportUnit: string;

minPixelValue: number;

}

const defaultsProp: IdefaultsProp = {

unitToConvert: "px",

viewportWidth: 375,

unitPrecision: 5,

viewportUnit: "vw",

fontViewportUnit: "vw",

minPixelValue: 1,

};

function toFixed(number: number, precision: number) {

const multiplier = Math.pow(10, precision + 1),

wholeNumber = Math.floor(number * multiplier);

return (Math.round(wholeNumber / 10) * 10) / multiplier;

}

function createPxReplace(

viewportSize: number,

minPixelValue: number,

unitPrecision: number,

viewportUnit: any

) {

return function ($0: any, $1: any) {

if (!$1) return;

const pixels = parseFloat($1);

if (pixels <= minPixelValue) return;

return toFixed((pixels / viewportSize) * 100, unitPrecision) + viewportUnit;

};

}

const templateReg: RegExp = /([sS]+)/gi;

const pxGlobalReg: RegExp = /(d+)px/gi;

function vitePluginStyleVWLoader(customOptions: IdefaultsProp = defaultsProp) {

return {

name: "vite-plugin-style-vw-loader",

transform(code: any, id: any) {

customOptions = Object.assign(defaultsProp, customOptions);

if (/.vue$/.test(id)) {

let _source = "";

if (templateReg.test(code)) {

_source = code.match(templateReg)[0];

}

if (pxGlobalReg.test(_source)) {

const $_source = _source.replace(

pxGlobalReg,

createPxReplace(

customOptions.viewportWidth,

customOptions.minPixelValue,

customOptions.unitPrecision,

customOptions.viewportUnit

)

);

code = code.replace(_source, $_source);

}

}

return { code };

},

};

}

export default vitePluginStyleVWLoader;

修改tsconfig.node.json 配置为:

{

"compilerOptions": {

"composite": true,

"skipLibCheck": true,

"module": "ESNext",

"moduleResolution": "bundler",

"allowSyntheticDefaultImports": true

},

"include": ["vite.config.ts", "src/plugin/vite-plugin-style-vw-loader.ts"]

}

修改 vite.config.ts 配置为如下:

import { defineConfig, loadEnv } from "vite";

import vue from "@vitejs/plugin-vue";

import AutoImport from "unplugin-auto-import/vite";

import Components from "unplugin-vue-components/vite";

import { VantResolver } from "@vant/auto-import-resolver";

import path from "path";

import postcsspxtoviewport8plugin from "postcss-px-to-viewport-8-plugin";

import vitePluginStyleVwLoader from "./src/plugin/vite-plugin-style-vw-loader";

export default defineConfig(({ command, mode }) => {

const env = loadEnv(mode, process.cwd(), "VITE_");

console.log(env);

const port: number = (env.VITE_APP_PORT as any) || 80;

return {

base: env.VITE_APP_CONTEXT_PATH,

plugins: [

vitePluginStyleVwLoader({

unitToConvert: "px",

viewportWidth: 375,

unitPrecision: 5,

viewportUnit: "vw",

fontViewportUnit: "vw",

minPixelValue: 1,

}),

AutoImport({

imports: ["vue", "vue-router"],

dts: "src/auto-import.d.ts",

}),

Components({

dirs: ["src/components"],

dts: "src/components.d.ts",

resolvers: [VantResolver()],

}),

vue(),

],

resolve: {

alias: {

"@": path.resolve("./src"),

},

},

server: {

host: true,

port: Number(port),

open: true,

proxy: {

[env.VITE_APP_BASE_API]: {

target: env.VITE_PROXY_TARGET_URL,

changeOrigin: true,

rewrite: (path) =>

path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),

},

},

},

css: {

postcss: {

plugins: [

postcsspxtoviewport8plugin({

unitToConvert: "px",

viewportWidth: 375,

unitPrecision: 5,

propList: ["*"],

viewportUnit: "vw",

fontViewportUnit: "vw",

selectorBlackList: [],

minPixelValue: 1,

mediaQuery: true,

replace: true,

exclude: [],

include: [],

landscape: false,

landscapeUnit: "vw",

landscapeWidth: 1024,

}),

],

},

},

};

});

这样自定义样式+行内样式 px都会转vw了

相关知识

vue3
移动端
手机移动端快速开发
如何从零高效的开发一款适配 Android 和 iOS 的移动端App
Html+Css+js实现春节倒计时效果(移动端和PC端)
移动Web实训DAY
一分钟告诉你建行移动端网络学习怎么学
简约排版鲜花植物类移动端店铺首页
基于深度卷积神经网络的移动端花卉识别系统
电商平台移动端应用开发及维护服务合同.doc

网址: vue3 + ts + vite 移动端适配 https://www.huajiangbk.com/newsview948688.html

所属分类:花卉
上一篇: [移动端适配]从一个祖传项目谈移
下一篇: 手机淘宝——flexible.j

推荐分享