移动屏幕适配自定义程度高 如何适配不同的屏幕尺寸(vant4 vue3 移动, pc稍微调整)

260 阅读3分钟

Vue3 移动端自适应方案教程(更新代码最底部)

移动项目 一般是陪的是手机和平板,有可能也会需要适配电脑客户端,介绍下我的思路

1. 基于postcss 去做vw 的适配,这里需要做文件的拆分,要不然无法区分viewportwidth

  • 对于同一个页面进行UI拆分,js 逻辑共用原则, 然后 postcss 通过文件名来设置不同的viewportwidth(index.vue index-pad.vue index.js 公共逻辑存放)
    • 上面的做法不利于组建的拆分,一旦拆分组件多了就会很复杂

2. JS 和 scss 结合判断

  • 首先我们写一个 scss 转换的函数 来转换 手机和平板的尺寸
$phoneViewport: 375;
$padViewport: 800;

@function phone($px) {
    @return calc(#{$px * 100vmin} / #{$phoneViewport});
}

@function pad($px) {
    @return calc(#{$px * 100vmin} / #{$padViewport});
}
  • 然后写一个JS 实现同样的功能 获取设备类型,转换尺寸
import { useWindowSize } from '@vant/use' //vant获取屏幕尺寸,可自行替换

import { ref, watch } from 'vue'

// phone 手机 pad 平板 设备类型

export type ScreenTypeReutrn = 'phone' | 'pad'
// 此尺寸对应 pxToVw.scss 里面的尺寸,需要保持一致
const viewport: Record<ScreenTypeReutrn, number> = {
    phone: 375,
    pad: 800,
}

//如果方法不准确可以自己调整,如果原生webview可以提供js变量来区分,就是用 js 来判断
export const screenType = (): ScreenTypeReutrn => {
    const big = window.matchMedia('(min-width: 550px) and (min-height: 550px)').matches
    if (!big) {
        return 'phone'
    } else {
        return 'pad'
    }
}

export const ScreenTypeHook = () => {
    const type = ref<ScreenTypeReutrn>(screenType())
    const { width, height } = useWindowSize()
    watch([width, height], () => {
        type.value = screenType()
    })
    return {
        type,
    }
}

// 可以根据屏幕类型传入不同的值 pxToVw(screenType() === ' phone' ? 10 : 15)
export const pxToVw = (num: number): string => {
    const type = screenType()
    const tmp = num / viewport[type]
    return `${(tmp * 100).toFixed(6)}vmin`
}

export const phone = (num: number): string => {
    const tmp = num / viewport['phone']
    return `${(tmp * 100).toFixed(6)}vmin`
}

export const pad = (num: number): string => {
    const tmp = num / viewport['pad']
    return `${(tmp * 100).toFixed(6)}vmin`
}

export const calcSize = (phone: number, pad: number) => {
    const type = screenType()
    return type === 'phone' ? phone : pad
}
  • 直接在.vue文件中使用
<template>
    <div :device-type="deviceType" class="page">
        <van-nav-bar title="屏幕适配" fixed />
        <div class="test">测试字体</div>
        <div class="test2"></div>
    </div>
</template>

<script setup lang="ts">
import { ScreenTypeHook } from '@/fitScreen'
const deviceType = ScreenTypeHook().type
</script>

<style scoped lang="scss">
.page[device-type='phone'] {
    font-size: phone(16);
    .test {
        color: red;
    }
    .test2 {
        margin-top: phone(8);
        background-color: red;
        width: 80vw;
        height: 20vh;
    }
}

.page[device-type='pad'] {
    font-size: pad(20);
    .test {
        color: purple;
    }

    .test2 {
        margin-top: pad(8);
        background-color: purple;
        width: 40vw;
        height: 40vh;
    }
}
</style>
  • 第三方的css 修改 可以直接在app.vue 中全局使用 scss函数一定要在 #{} 里面使用,否则方法无效
<div class="vantfit" :deviceType v-show="showPage">
.vantfit[deviceType='phone'] {
    --van-cell-font-size: #{phone(15)};
    --van-cell-line-height: #{phone(24)};
    --van-cell-vertical-padding: #{phone(10)};
    --van-cell-icon-size: #{phone(15)};
    --van-nav-bar-icon-color: '#ffffff';
    --van-nav-bar-height: #{phone(46)};
    --van-line-height-lg: #{phone(46)};
    --van-nav-bar-arrow-size: #{phone(16)};
    --van-nav-bar-title-font-size: #{phone(18)};
    --van-nav-bar-title-text-color: '#222222';
    --van-font-size-md: #{phone(16)};
}

.vantfit[deviceType='pad'] {
    --van-cell-font-size: #{pad(15)};
    --van-cell-line-height: #{pad(24)};
    --van-cell-vertical-padding: #{pad(10)};
    --van-cell-icon-size: #{pad(15)};
    --van-nav-bar-icon-color: '#ffffff';
    --van-nav-bar-height: #{pad(60)};
    --van-line-height-lg: #{pad(60)};
    --van-nav-bar-arrow-size: #{pad(16)};
    --van-nav-bar-title-font-size: #{pad(30)};
    --van-nav-bar-title-text-color: '#222222';
    --van-font-size-md: #{pad(16)};
}
如果要要适配pc 可以自己在加一个屏幕尺寸判断或者

好的,我来基于您的代码重新优化教程。

Vue3 移动端自适应方案教程

1. 概述

这是一个基于 Vue3 + TypeScript 的移动端自适应方案,特别适合企业级应用开发:

  • 自动识别设备类型(手机/平板)
  • 基于 vmin 的等比例缩放
  • 支持企业应用环境判断
  • 媒体查询实现动态切换
  • 支持 SCSS 混入

2. 文件结构

src/
├── common/
│   └── xm.ts           # 设备类型判断
├── fitScreen/
│   ├── config.ts       # 视口配置
│   ├── index.ts        # 核心逻辑
│   └── pxToVw.scss     # SCSS 工具函数
└── main.ts             # 入口文件

3. 核心实现

3.1 设备类型判断 (src/common/xm.ts)

export const getDeviceType = (callback: (type: DeviceInfoType) => void) => {
    
    // 通用环境:使用媒体查询判断设备类型
    const isPad = window.matchMedia('(min-width: 550px) and (min-height: 550px)').matches
    console.log('getDeviceType', `是平板?${isPad}`, `是手机?${!isPad}`)
    
    callback(isPad ? 'pad' : 'phone')
}

3.2 视口配置 (src/fitScreen/config.ts)

export const VIEWPORT = {
    phone: 375,  // 手机设计稿宽度
    pad: 800,    // 平板设计稿宽度
} as const

export const setViewportVars = () => {
    document.documentElement.style.setProperty('--phone-viewport', VIEWPORT.phone.toString())
    document.documentElement.style.setProperty('--pad-viewport', VIEWPORT.pad.toString())
}

3.3 核心逻辑 (src/fitScreen/index.ts)

import { DeviceInfoType } from '@/common/type'
import { getDeviceType } from '@/common/xm'
import { useWindowSize } from '@vant/use'
import { ref, watch } from 'vue'
import { VIEWPORT } from './config'

// 设备类型响应式引用
export const deviceType = ref<DeviceInfoType>('phone')

// 监听设备类型变化
getDeviceType((type) => {
    deviceType.value = type
})

// 监听窗口大小变化
const { width, height } = useWindowSize()
watch([width, height], () => {
    getDeviceType((type) => {
        deviceType.value = type
    })
})

// 转换函数工厂
const createVwConverter = (viewportSize: number): PxToVwFuncType => {
    return (num: number): string => {
        const tmp = num / viewportSize
        return `${(tmp * 100).toFixed(6)}vmin`
    }
}

// 导出工具函数
export const pxToVw = (num: number): string => {
    return createVwConverter(VIEWPORT[deviceType.value])(num)
}

export const phone = createVwConverter(VIEWPORT.phone)
export const pad = createVwConverter(VIEWPORT.pad)

export const calcSize = (phoneSize: number, padSize: number): number => {
    return deviceType.value === 'phone' ? phoneSize : padSize
}

3.4 SCSS 工具函数 (src/fitScreen/pxToVw.scss)

@use 'sass:map';

@function phone($px) {
    @return calc(#{$px * 100vmin} / var(--phone-viewport));
}

@function pad($px) {
    @return calc(#{$px * 100vmin} / var(--pad-viewport));
}

4. 使用指南

4.1 初始化配置

在 main.ts 中初始化:

import { setViewportVars } from './fitScreen/config'

// 设置视口变量
setViewportVars()

4.2 在组件中使用

<template>
  <div class="container">
    <div :style="{ fontSize: titleSize }">动态大小的标题</div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { pxToVw, deviceType } from '@/fitScreen'

// 响应式计算大小
const titleSize = computed(() => pxToVw(deviceType.value === 'phone' ? 16 : 24))
</script>

<style lang="scss" scoped>
@import '@/fitScreen/pxToVw.scss';

.container {
    // 手机端样式
    padding: phone(15);
    margin: phone(10);
    
    // 平板端样式
    @media (min-width: 550px) {
        padding: pad(20);
        margin: pad(15);
    }
}
</style>

5. 最佳实践

5.1 设备判断

// 封装设备类型判断 Hook
import { computed } from 'vue'
import { deviceType } from '@/fitScreen'

export const useDevice = () => {
    const isPhone = computed(() => deviceType.value === 'phone')
    const isPad = computed(() => deviceType.value === 'pad')
    
    return { isPhone, isPad }
}

5.2 响应式布局

.layout {
    // 基础样式
    display: flex;
    
    // 手机端布局
    flex-direction: column;
    padding: phone(10);
    
    // 平板端布局
    @media (min-width: 550px) {
        flex-direction: row;
        padding: pad(20);
    }
}

5.3 组件封装

// 封装常用的自适应大小计算
export const useAdaptiveStyles = () => {
    const styles = computed(() => ({
        fontSize: pxToVw(16),
        spacing: pxToVw(20),
        padding: deviceType.value === 'phone' 
            ? `${phone(10)} ${phone(15)}`
            : `${pad(15)} ${pad(20)}`
    }))
    
    return { styles }
}

6. 注意事项

  1. 设备判断

    • 优先使用企业环境的设备信息
    • 降级使用媒体查询判断
    • 考虑横竖屏切换场景
  2. 性能优化

    • 缓存计算结果
    • 避免频繁重计算
    • 使用 computed 属性
  3. 样式处理

    • 使用 SCSS 混入复用样式
    • 合理使用媒体查询
    • 避免硬编码像素值
  4. 类型安全

    • 使用 TypeScript 类型声明
    • 避免使用 any 类型
    • 做好类型推导

7. 优势特点

  1. 企业级应用支持

    • 支持企业应用商店环境
    • 兼容通用浏览器环境
    • 自动降级处理
  2. 响应式设计

    • 自动识别设备类型
    • 动态适配屏幕大小
    • 平滑过渡效果
  3. 开发体验

    • TypeScript 类型支持
    • SCSS 工具函数
    • 简单易用的 API
  4. 可维护性

    • 集中配置管理
    • 模块化设计
    • 清晰的代码结构

这个适配方案特别适合企业级应用开发,能够很好地处理不同设备类型的适配需求,同时保持了良好的开发体验和代码可维护性。