25 Vue3之如何开发移动端并适配

news2024/9/28 3:19:23

开发移动端最主要的就是适配各种手机

vw vh是相对viewport 视口的单位,配合meta标签可以直接使用,无需计算

1vw=1/100视口宽度

1vh=1/100视口高度

当前屏幕视口是375像素,1vw就是3.75px

postCss 提供了 把Css 转换AST的能力,类似于Babel,为此我们可以编写一个postCss插件用于将px转换为vw

前置知识

px 固定的单位不会随着屏幕大小的变化而变化

百分比

  • 百分比是子元素占父元素的宽度,然后让子元素撑起父元素的高度
  • 其中百分比只能勉强解决容器的适配(比如高度无法用百分比表示),做不到字体的适配
  • 字体和高度适配也需配合下面的rem方案

flex

     跟百分比一样只能解决容器的适配不能处理字体的适配

rem

  • 在之前我们用的是rem 根据根节点HTML font-size 去做缩放 
  • rem r=root 1rem = html 假如html根节点font-size =16px 1rem = 16px
  • 有个问题375屏幕下适合多少HTML font-size 并不清楚之前引入的是淘宝的flexible.js来计算的,这个方案就额外多了计算的开销
vh、vw
  •  vw、vh是基于视口的布局方案,所以这个meta元素的视口必须声明。(解决宽高自动适配)
  • 为什么加meta标签 默认的视口可能是大于屏幕的尺寸会出现滚动条

  • vw vh是相对viewport 视口的单位,配合meta标签可以直接使用,无需计算

    1vw=1/100视口宽度

    1vh=1/100视口高度

    当前屏幕视口是375像素,1vw就是3.75像素

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no“>

移动设备具有各种不同的屏幕尺寸和分辨率,例如智能手机和平板电脑。为了提供更好的用户体验,网页需要根据设备的屏幕宽度进行自适应布局。如果不设置width=device-width,移动设备会按照默认的视口宽度(通常是较宽的桌面屏幕)来渲染网页,导致网页内容在移动设备上显示不正常,可能出现内容被截断或需要水平滚动的情况

初始化项目

npm init vite@latest

cnpm i 

cnpm i less less-loader

cnpm i @vueuse/core

postCss

https://cn.vitejs.dev/config/shared-options.html#css-postcss

发现vite已经内置了postCss

https://www.postcss.com.cn/

postCss 提供了 把Css 转换AST的,类似于Babel,为此我们可以编写一个插件用于将px转换为vw

根目录新建一个plugins文件夹新建两个文件pxto-viewport.ts type.ts 

然后在 tsconfig.node.json 的includes 配置 "plugins/**/*",

compilerOptions 配置 noImplicitAny:false

tsconfig.node.json配置

postcss-px-to-viewport.ts

// postcss的插件已经是vite内置了,所以不需要再单独安装了

import type { Options } from "./type.ts";
import type { Plugin } from "postcss";
const defaultOptions = {
  viewPortWidth: 375, //视窗的宽度,对应的是我们设计稿的宽度一般是375,ui设计稿宽度是多少就是多少
  mediaQuery: false,
  unitToConvert: "px",
};
export const pxToViewport = (
  options: Options = defaultOptions
): Plugin => {
  const opt = Object.assign({}, defaultOptions, options);
  return {
    postcssPlugin: "postcss-px-to-viewport",
    //  AtRulede等钩子函数
    //
    //css节点都会经过这个钩子
    Declaration(node) {
      // console.log(node);
      console.log(node.prop, node.value);
      // console.log("opt.viewPortWidth", opt.viewPortWidth); // 375

      const value = node.value;
      //匹配到px 转换成vw
      if (value.includes(opt.unitToConvert)) {
        const num = parseFloat(value); //考虑到有小数的情况
        const transformValue =
          (num / opt.viewPortWidth) * 100;
        node.value = `${transformValue.toFixed(2)}vw`; //转换之后的值
      }
    },
  };
};

 type.ts

export interface Options {
    viewPortWidth?: number;
    mediaQuery?: boolean;
    unitToConvert?: string;
}

vite.config.ts配置

引入我们写好的插件

https://cn.vitejs.dev/config/shared-options.html#css-postcss参考配置

import { pxToViewport } from "./plugins/postcss-px-to-viewport";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  css: {
    postcss: {
      plugins: [pxToViewport()],
    },
  },
});

用户可自定义设计稿宽度 (可省略在插件内部已给了默认值)

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { pxToViewport } from "./plugins/postcss-px-to-viewport";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  css: {
    postcss: {
      plugins: [
        pxToViewport({
          unitToConvert: "px", // 要转化的单位
          viewPortWidth: 750, // UI设计稿的宽度
        }),
      ],
    },
  },
});

组件中使用

自适应效果图

未使用插件前明显感觉中间被挤压了

使用插件后

全局换肤案例

全局字体更改案例

完整示例代码 

main.ts中注释掉初始style.css样式

// postcss的插件已经是vite内置了,所以不需要再单独安装了

import type { Options } from "./type.ts";
import type { Plugin } from "postcss";
const defaultOptions = {
  viewPortWidth: 375, //视窗的宽度,对应的是我们设计稿的宽度一般是375,ui设计稿宽度是多少就是多少
  mediaQuery: false,
  unitToConvert: "px",
};
export const pxToViewport = (
  options: Options = defaultOptions
): Plugin => {
  const opt = Object.assign({}, defaultOptions, options);
  return {
    postcssPlugin: "postcss-px-to-viewport",
    //  AtRulede等钩子函数
    //
    //css节点都会经过这个钩子
    Declaration(node) {
      // console.log(node);
      console.log(node.prop, node.value);
      // console.log("opt.viewPortWidth", opt.viewPortWidth); // 375

      const value = node.value;
      //匹配到px 转换成vw
      /* 
      // 无法处理 border: 1px solid red;
      if (value.includes(opt.unitToConvert)) {
        const num = parseFloat(value); //考虑到有小数的情况
        const transformValue =
          (num / opt.viewPortWidth) * 100;
        node.value = `${transformValue.toFixed(2)}vw`; //转换之后的值
      } */
      // 能处理 border: 1px solid red;
      if (value.includes(opt.unitToConvert)) {
        const regexp = new RegExp(
          `\\d+${opt.unitToConvert}{1}`,
          "gi"
        );
        const nodeVal = value.replace(regexp, (match) => {
          const num = parseFloat(match);
          const transformValue = Number(
            (num / opt.viewPortWidth) * 100
          );
          return transformValue.toFixed(2) + "vw";
        });
        node.value = nodeVal;
      }
    },
  };
};

官方插件postcss-px-to-viewport

已经帮我们处理好了各种兼容性


npm install postcss-px-to-viewport -D

vite.config.ts配置

可能vant第三库会存在挤压得问题可设置成375

const designWidth = webpack.resourcePath.includes(path.join('node_modules', 'vant')) ? 375 : 750;

import { fileURLToPath, URL } from 'url'
 
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import postcsspxtoviewport from "postcss-px-to-viewport" //插件
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx()],
  css: {
    postcss: {
      plugins: [
        postcsspxtoviewport({
          unitToConvert: 'px', // 要转化的单位
          viewportWidth: 750, // UI设计稿的宽度
          unitPrecision: 6, // 转换后的精度,即小数点位数
          propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
          viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
          fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
          selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
          minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
          mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
          replace: true, // 是否转换后直接更换属性值
          landscape: false // 是否处理横屏情况
        })
      ]
    }
  },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

 postcss-px-to-viewport.d.ts声明文件

declare module 'postcss-px-to-viewport' {
 
    type Options = {
        unitToConvert: 'px' | 'rem' | 'cm' | 'em',
        viewportWidth: number,
        viewportHeight: number, // not now used; TODO: need for different units and math for different properties
        unitPrecision: number,
        viewportUnit: string,
        fontViewportUnit: string,  // vmin is more suitable.
        selectorBlackList: string[],
        propList: string[],
        minPixelValue: number,
        mediaQuery: boolean,
        replace: boolean,
        landscape: boolean,
        landscapeUnit: string,
        landscapeWidth: number
    }
 
    export default function(options: Partial<Options>):any
}

引入声明文件 tsconfig.app.json postcss-px-to-viewport.d.ts跟vite.ts同级

{
  "extends": "@vue/tsconfig/tsconfig.web.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue", "postcss-px-to-viewport.d.ts"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172099.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode --- 416周赛

题目列表 3295. 举报垃圾信息 3296. 移山所需的最少秒数 3297. 统计重新排列后包含另一个字符串的子字符串数目 I 3298. 统计重新排列后包含另一个字符串的子字符串数目 II 一、举报垃圾信息 直接用哈希表统计bannedWords中的单词&#xff0c;遍历message中出现的垃圾信息…

WiFi无线连接管理安卓设备工具:WiFiADB

介绍 WiFi ADB 使您能够通过 WiFi TCP/IP 连接直接在设备上轻松调试和测试 Android 应用&#xff0c;无需使用 USB 数据线。在启用 WiFi 上的 ADB 后&#xff0c;打开控制台将电脑连接到设备。 手机和电脑在同一个WiFi然后电脑上运行adb connect x.x.x.x:x命令即可 下载 谷…

Go语言开发后台框架不能只有CRUD还需有算法集成基础功能-GoFly框架集成了自然语言处理(NLP)分词、关键词提取和情感分析

前言 Go语言开发框架&#xff0c;我们要把Go的优势体现在框架中&#xff0c;不仅CRUD常规操作&#xff0c;还要把常用即有算力自己集成到框架中&#xff0c;而不是去购买第三方提供服务接口。作为开发者可以拓宽自己代码面&#xff0c;获取更多成就感&#xff0c;同时也提供自…

戴尔PowerEdge R840服务器亮黄灯 不开机

最近接修到一台东莞用户的DELL PowerEdge R840 服务器因为意外断电后&#xff0c;无法正常开机的问题&#xff0c; 大概故障现象是 插上电源线 按卡机按钮无响应&#xff0c;无法开机&#xff0c;无显示输出&#xff0c;工程师到现场检修&#xff0c;经过idrac中日志分析&#…

商标是什么?为何对企业至关重要?

商标作为企业的核心标识&#xff0c;不仅是区分商品与服务的关键&#xff0c;更是企业品牌塑造、市场区分和消费者信任建立的基石。那么&#xff0c;商标究竟是什么&#xff1f;它又为何对企业如此重要呢&#xff1f; 商标的定义及类型 商标&#xff08;Trademark&#xff09;…

Python获取百度翻译的两种方法

一、引言 百度是我们常用的搜索工具&#xff0c;其翻译是与爱词霸合作&#xff0c;总体看其反应速度较快&#xff0c;可以作为项目中重要的翻译工具。根据大家的需要&#xff0c;现提供两种Python获取百度翻译的两种办法&#xff1a; 二、requests法 我们引用requests模块&a…

构建5G-TSN测试平台:架构与挑战

论文标题&#xff1a;Building a 5G-TSN Testbed: Architecture and Challenges 作者信息&#xff1a; Anna Agust-Torra, Marc Ferr-Mancebo, David Rincn-Rivera, Cristina Cervell Pastor, Sebasti Sallent-Ribes&#xff0c;来自西班牙巴塞罗那的加泰罗尼亚理工大学&…

裁剪视频如何让画质不变?一文教会你

当我们想要从一段视频中提取精华&#xff0c;裁剪视频就成了必不可少的技能。 但是&#xff0c;如何做到在裁剪过程中不损害画质&#xff0c;保持视频原有的清晰度和流畅度呢&#xff1f; 这不仅需要技巧&#xff0c;还需要对视频编辑有一定的了解。 本文将为你介绍四种裁剪…

Redis篇(数据类型)

目录 讲解一&#xff1a;简介 讲解二&#xff1a;常用 一、String类型 1. 简介 2. 常见命令 3. Key结构 4. 操作String 5. 实例 二、Hash类型 1. 简介 2. 常见命令 3. 3操作hash 4. 实例 三、List类型 1. 简介 2. 特征 3. 应用场景 4. 常见命令 5. 操作list …

13.安卓逆向-frida基础-编写hook脚本1

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信。 工…

外国电影演员识别系统源码分享

外国电影演员识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

AI产品经理必知:核心人工智能技术概览

第一章&#xff1a;AI产品经理是否需要懂技术及其程度 在当今AI行业快速发展的背景下&#xff0c;作为一位AI产品经理&#xff0c;理解并掌握一定的AI技术知识不仅是锦上添花&#xff0c;更是不可或缺的素质。那么&#xff0c;AI产品经理究竟需要懂到何种程度的技术呢&#xf…

国内车市销量激增,理想成功超越BBA

文/王俣祺 导语&#xff1a;随着“金九银十”的到来&#xff0c;国内汽车市场迎来了一个充满活力的开局。乘用车市场的销量已经迎来新的突破&#xff0c;彰显出中国汽车市场的韧性和潜力。尤为引人注目的是&#xff0c;新能源汽车销量同样激增&#xff0c;成为推动市场增长的重…

C++--IO流

目录 1. C语言的输入与输出 2. 流是什么 3. CIO流 4 stringstream的简单介绍 1. C语言的输入与输出 C 语言中我们用到的最频繁的输入输出方式就是 scanf () 与 printf() 。 scanf(): 从标准输入设备 ( 键 盘 ) 读取数据&#xff0c;并将值存放在变量中 。 printf(): 将…

C++ : 多态

1. 多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态。 举个栗子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&#xff1b;学…

通过队列实现栈

请你仅使用两个队列实现一个后入先出&#xff08;LIFO&#xff09;的栈&#xff0c;并支持普通栈的全部四种操作&#xff08;push、top、pop 和 empty&#xff09;。 实现 MyStack 类&#xff1a; void push(int x) 将元素 x 压入栈顶。int pop() 移除并返回栈顶元素。int to…

基于微信小程序爱心领养小程序设计与实现(源码+定制+开发)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

基于Hive和Hadoop的电信流量分析系统

本项目是一个基于大数据技术的电信流量分析系统&#xff0c;旨在为用户提供全面的通信数据和深入的流量使用分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 Spark…

无人船在海洋勘探领域的应用!

一、具体应用 海底地形测绘&#xff1a; 无人船可以搭载多波束测深仪等先进设备&#xff0c;进行高精度的海底地形测绘。这些设备能够生成详细的海底地形图&#xff0c;为海洋工程设计和施工提供详尽的水下地形资料。 海底资源勘探&#xff1a; 通过搭载磁力仪、重力仪等地…

安卓手机视频被误删怎么恢复,这3个方法满足你

视频作为一种直观、生动的记录方式&#xff0c;受到了广大用户的喜爱&#xff0c;许多朋友们都喜欢用视频来记录生活或工作中的重要时刻。但有时候会遇到突发情况&#xff0c;导致这些重要视频丢失。别担心&#xff0c;下面小编将同您一起探索这视频恢复的方法&#xff0c;轻松…