vue3移动端适配的解决方案


前言

最近在给公司内部做一个BBS论坛,需要在电脑和手机上都可以操作,所以需要做移动端的适配,下面是我在开发后觉得不错的一些解决方案,分享给大家。


一、使用插件

在vue2的时候我们可以使用lib-flexible + postcss-pxtorem 去对移动端进行适配,不过lib-flexible这个过度方案弃用了,所以我们可以在vue3中用amfe-flexible + postcss-pxtoremvant也推荐用这两搭配,老实说,vant是真的香(づ ̄3 ̄)づ。

vant 推荐使用在=》进阶用法=》Rem 布局适配 :传送门

下面来看一下这两插件怎么用吧,我们先执行命令安装这两插件(测试用的vue版本是3.2.13)

amfe-flexible:目前执行默认指向2.2.1版本

npm i -S amfe-flexible

postcss-pxtorem 目前执行默认指向6.0.0版本

npm install postcss-pxtorem --save-dev

安装完后我们先在main.js中引入amfe-flexible

import 'amfe-flexible'

接着在项目根目录新建一个postcss.config.js文件

Vue3脚手架项目
	|-public
	|-src
	|-postcss.config.js

① 纯wap项目

如果你的项目不考虑放PC端的页面的话,直接把下面的代码拷贝到上面创建的js文件里就好了:

// postcss.config.js
module.exports = {
    plugins: {
        'postcss-pxtorem': {
            rootValue({ file }) {
                return file.indexOf('vant') !== -1 ? 37.5 : 75; // 因为vant框架是以375px的稿子为基础的,所以需要适配一下
            },
            propList: ['*'], // 需要转换的css属性,默认*全部
        }
    }
}

配置完之后我们就可以在项目中以px为单位去开发了,是的,不用我们手动敲rem转换去开发了,PS设计稿的宽度以750px为基准,否则需要自己调一下,开发时稿子是1px,你就写1px就好了,插件会帮我们换算成rem。

效果:

我用vant4简单搭了个项目,从GIF中可以看到px都自动转化成rem了,vue的logo我给了375px的宽高,当窗口宽度为750像素时,logo的实际宽高是375px,也就是说我们只要按750的设计稿去写,就能以1:1进行页面还原了。

在这里插入图片描述

Demo:

如果你的项目完全不用考虑pc端的话,可以参考参考这个demo。
下载地址:vue3-page-adapter-m


② pc&wap混合项目(我放弃了)

如果你的项目既要放手机端的页面,又要放电脑端的页面,那么我是不推荐你用amfe-flexible + postcss-pxtorem去适配你的项目的,至于为什么,可以看看下面我踩的坑。

本地工作目录:

Vue3脚手架项目
	|-src
		|-views
			|-m
			|-pc

比如说你的工作目录有两个文件夹,一个用来放手机端的页面,一个用来放电脑端的页面,那么我们肯定是不想pc文件夹里的页面被转换成rem,也不想pc端的ui框架(element plus)被转换成rem,那么postcss-pxtorem提供了下面4中形式来处理是否需要把pc转化成rem:

  • rootValue({ file }):转换比率
  • propList[]: 需要转换的css属性,默认*全部,比如不想字体被转换,那就在数组里面加入'!font-size'
  • selectorBlackList[]:不需要转换的class类名
  • exclude:不需要转换的文件夹,可以使用三种形式:字符串(String)、正则表达式(Regexp)、 函数(Function

首先为了不让pc文件夹下面的页面自动转化成rem,我配置了exclude参数来区分,之后pc文件夹下的vue文件的样式确实不会自动转换了,但是引入element plus后,拖动窗口你会发现el组件自动缩放了,是的,就算你在配置好的pc文件夹里使用去第三方框架,第三方框架还是会自动转化成rem,于是我配置了selectorBlackList,于是我把有关el:root的类名全部设置成不自动转换,之后el组件确实不会自动缩放了,但是这样的话手机端的vant组件不会自动缩放了,除非手动去设置像素大小,这是因为第三方框架的一些基础属性都是放在:root下,具体看下面的GIF:

至于为什么要设置:root类名,因为el组件的默认值都在这个类名下,不排除的话一些字体会转化成rem,导致字体自动缩放;另外你可能还会问el组件的默认值都是--el开头的属性,为什么不用propList去排除?我试过,不行)

在这里插入图片描述

相关代码:

// postcss.config.js
module.exports = {
    plugins: {
        'postcss-pxtorem': {
            rootValue({ file }) {
                return file.indexOf('vant') !== -1 ? 37.5 : 75; // 因为vant框架是以375px的稿子为基础的,所以需要适配一下
            },
            propList: ['*'], // 需要转换的css属性,默认*全部
            selectorBlackList: ['el',':root'], // 不需要转换的class类名
            exclude: 'src\\views\\pc' // 不需要转换的文件夹
            // exclude: /src\\views\\pc/i
            // exclude: function (file) { return file.indexOf('src\\views\\pc') !== -1; }
        }
    }
}

接着我又尝试在rootValue里有关element-plus组件的都返回false,结果vant框架能缩放了,element框架能不自动缩放了,但是:root类名里的--el的一些默认值都被替换成了Infinityrem,所以el的一些字体、高度、圆角等默认值都不会有了,(╯°Д°)╯︵┻━┻,我选择狗带了。

在这里插入图片描述

相关代码:

// postcss.config.js
module.exports = {
    plugins: {
        'postcss-pxtorem': {
            rootValue({ file }) {
                if (file.indexOf('element-plus') !== -1) return false
                return file.indexOf('vant') !== -1 ? 37.5 : 75; // 因为vant框架是以375px的稿子为基础的,所以需要适配一下
            },
            propList: ['*'], // 需要转换的css属性,默认*全部
            selectorBlackList: ['el'], // 不需要转换的class类名
            exclude: 'src\\views\\pc' // 不需要转换的文件夹
            // exclude: /src\\views\\pc/i
            // exclude: function (file) { return file.indexOf('src\\views\\pc') !== -1; }
        }
    }
}

经过一顿操作后,还是没有办法很好的用amfe-flexible + postcss-pxtorem去兼顾pc+wap的项目,并且考虑后续pc端不可能只用element框架,所以我放弃这种方案了


二、老方案

最后,为了项目里能同时兼顾pc端和wap端,我还是选择用了以前写原生时的方案,不清楚的可以看看我之前写的文章:传送门,下面来看一下可行性吧。

Vue3脚手架项目
	|-public
		|-index.html

我们先在index.html文件的<head>标签里加入下面的代码:

  <script>
    const isMobile = () => {
      const flag = navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)
      return flag ? true : false;
    }
    if (isMobile()) {
      //封装响应式像素方法,初始化单位,实现手机端1rem=100px
      const responsivePX = () => {
        //获取页面的宽度
        let deviceWidth = document.documentElement.clientWidth;
        //如果页面大于750,即px端的页面,则把html的像素锁死在100px
        if (deviceWidth > 750) deviceWidth = 750;
        document.documentElement.style.fontSize = deviceWidth / 7.5 + 'px';
      }
      // 第一次初始化像素大小
      responsivePX();
      // 监听窗口二次刷新像素大小
      window.onresize = () => {
        responsivePX();
      };
    }
  </script>

这段代码的大致功能是监听到设备是移动端时,就会根据窗口的大小去动态设置html的字体大小,之后我们就可以在项目中以rem为单位去开发移动端了,为了防止字体过大,我做了限制,就是当屏幕大于750时,最大字体仍旧是100px,当屏幕刚好等于750时,rem和px的比例为1:100,也就是说用750像素的设计稿去开发,比如页面宽度是100px,那么我们代码里写1rem就行了,相信都能看懂,不多说了。

效果:

用老方案的话完全不用担心pc端会自动缩放了,因为在pc环境我们压根就没动态设置html根标签的字体,唯一比较麻烦的是写移动端页面时要换算成rem,还有就是因为不会自动把px转化成rem,所以第三方框架并不会自动缩放,比如vant的组件,它是有默认的px值的,如果你想要某个组件自动缩放的话,手动设置一下rem就好,其实一些组件不设置缩放我反而会觉得看得更舒服,比如tabbar,这个因人而异吧,问题不大。需要注意的是如果你用了vant的tabbar,会有一部分视野挡住内容,需要根据你设置的高度或默认的高度去设置下padding,具体可以看下GIF:

在这里插入图片描述


Demo:

如果你的项目需要把pc端和wap端放一块写,可以参考参考这个demo。
下载地址:vue3-page-adapter-pc-m

<think>嗯,用户问的是如何在Vue3项目中实现移动端到大屏的适配方案。首先,我需要回忆一下移动端适配的常用方法。根据之前的引用内容,用户可能已经了解了一些rem适配方案,比如rem配合媒体查询、js动态设置或者使用VW。但这次的问题是要适配移动端到大屏,可能需要更灵活的响应式设计。 首先,我应该考虑Vue3的特性,比如组合式API和响应式工具,可能可以用来动态调整布局。然后,适配方案可能需要结合多种方法,比如使用rem或vw作为单位,同时利用媒体查询来针对不同屏幕尺寸应用不同的样式。另外,大屏可能需要更多的布局调整,比如弹性布局或者栅格系统,这时候可能需要像Tailwind CSS这样的工具来简化响应式设计。 接着,用户可能需要的不仅仅是基本的rem适配,还需要元素尺寸的动态缩放。这时候,使用JavaScript监听窗口变化,动态计算根字体大小可能有效。同时,像scale-box这样的组件可能对大屏适配有帮助,特别是在保持比例的情况下缩放内容。 另外,图片和媒体的适配也很重要,可能需要使用响应式图片,或者像v-lazy这样的懒加载插件来优化性能。视口单位(vw/vh)和百分比布局的结合使用可能更灵活,适应不同屏幕尺寸。 还要考虑第三方库的支持,比如lib-flexible或者postcss-px-to-viewport,这些工具可以自动转换单位,简化开发流程。同时,自定义指令可能在需要动态调整元素尺寸时派上用场,比如根据屏幕大小改变字体或间距。 最后,测试环节不可忽视,需要确保不同设备和屏幕尺寸下的显示效果一致,可能推荐使用浏览器开发者工具进行多设备模拟测试。 需要综合这些方法,提供一个分步骤的解决方案,涵盖基础配置、动态缩放、布局调整、第三方工具和测试建议。同时,要确保回答结构清晰,步骤明确,帮助用户逐步实现适配。</think>### Vue3移动端到大屏适配方案分步解析 在Vue3项目中实现移动端到大屏的适配,需要结合响应式布局与动态缩放策略。以下是经过验证的完整解决方案: #### 一、基础适配方案 1. **视口单位+rem混合方案** ```javascript // main.js const setRootFontSize = () => { const baseWidth = 375 // 以iPhone6/7/8为基准 const scale = document.documentElement.clientWidth / baseWidth document.documentElement.style.fontSize = `${Math.min(scale, 4) * 100}px` // 限制最大缩放比例 } window.addEventListener(&#39;resize&#39;, setRootFontSize) setRootFontSize() ``` ```css /* 使用混合单位 */ .container { padding: 0.2rem 0.1vw; /* 横向用vw保持流动性,纵向用rem保持比例 */ font-size: clamp(14px, 0.16rem + 0.5vw, 24px); /* 动态字体大小 */ } ``` 该方案结合了rem的等比缩放和vw的视口响应特性[^2] 2. **响应式断点配置** ```javascript // breakpoints.js export const BREAKPOINTS = { MOBILE: 375, TABLET: 768, DESKTOP: 1280, LARGE_SCREEN: 1920 } ``` #### 二、大屏适配增强方案 1. **动态缩放容器** ```vue <template> <div ref="scaleContainer" class="scale-wrapper"> <slot></slot> </div> </template> <script setup> import { ref, onMounted, onBeforeUnmount } from &#39;vue&#39; const scaleContainer = ref(null) const baseWidth = 1920 // 设计稿基准宽度 const updateScale = () => { const { clientWidth } = document.documentElement const scale = clientWidth / baseWidth scaleContainer.value.style.transform = `scale(${scale}) translateX(-50%)` scaleContainer.value.style.width = `${baseWidth}px` } onMounted(() => { window.addEventListener(&#39;resize&#39;, updateScale) updateScale() }) onBeforeUnmount(() => { window.removeEventListener(&#39;resize&#39;, updateScale) }) </script> <style> .scale-wrapper { position: fixed; left: 50%; top: 0; transform-origin: 0 0; transition: transform 0.3s; } </style> ``` 2. **栅格系统配置** ```css /* 响应式栅格 */ .grid-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: clamp(10px, 1vw, 30px); } @media (min-width: 1280px) { .grid-container { grid-template-columns: repeat(4, 1fr); } } ``` #### 三、进阶优化方案 1. **PostCSS自动转换** ```javascript // postcss.config.js module.exports = { plugins: { &#39;postcss-px-to-viewport&#39;: { unitToConvert: &#39;px&#39;, viewportWidth: 375, // 移动端基准 viewportHeight: 667, unitPrecision: 5, propList: [&#39;*&#39;], viewportUnit: &#39;vw&#39;, fontViewportUnit: &#39;vw&#39;, selectorBlackList: [], minPixelValue: 1, mediaQuery: false, replace: true, exclude: [/node_modules/], landscape: false, landscapeUnit: &#39;vw&#39;, landscapeWidth: 1136 } } } ``` 2. **混合单位策略** ```css /* 弹性布局示例 */ .card { width: min(90vw, 1200px); /* 限制最大宽度 */ height: calc(100vh - 60px); /* 结合视口单位 */ margin: 0 auto; padding: max(2vh, 20px); } ``` #### 四、实践建议 1. **设备方向处理** ```javascript // 横竖屏检测 const checkOrientation = () => { if (window.matchMedia("(orientation: portrait)").matches) { document.body.classList.add(&#39;portrait&#39;) document.body.classList.remove(&#39;landscape&#39;) } else { document.body.classList.add(&#39;landscape&#39;) document.body.classList.remove(&#39;portrait&#39;) } } ``` 2. **性能优化** ```vue <template> <img :src="responsiveImage.url" :srcset="responsiveImage.srcset" sizes="(max-width: 768px) 100vw, 50vw" alt="responsive image" > </template> <script setup> import { computed } from &#39;vue&#39; const props = defineProps({ imageSet: Object }) const responsiveImage = computed(() => ({ url: props.imageSet.mobile, srcset: ` ${props.imageSet.mobile} 375w, ${props.imageSet.tablet} 768w, ${props.imageSet.desktop} 1280w ` })) </script> ``` ###
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值