乐于分享
好东西不私藏

Vue 项目移动端适配怎么做?这套方案从 PC 到手机全搞定

Vue 项目移动端适配怎么做?这套方案从 PC 到手机全搞定

响应式布局是现代 Web 开发的基础要求,但很多项目做得不够好。

PC 端好看,手机上一塌糊涂;或者用了 rem 适配,但字体大小在不同设备上还是不对。

这篇文章把 Vue 项目的移动端适配方案系统梳理一遍。

Tailwind CSS 响应式(推荐)

Tailwind 的响应式断点是目前最简洁的方案:

sm:  640px+md:  768px+lg:  1024px+xl:  1280px+2xl: 1536px+
<template>  <!-- 移动端单列,平板双列,PC 三列 -->  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">    <div v-for="item in items" :key="item.id">{{ item.name }}</div>  </div>  <!-- 移动端隐藏,PC 显示 -->  <aside class="hidden lg:block">侧边栏</aside>  <!-- 移动端显示,PC 隐藏 -->  <nav class="block lg:hidden">移动端导航</nav>  <!-- 响应式字体 -->  <h1 class="text-2xl md:text-3xl lg:text-4xl font-bold">标题</h1>  <!-- 响应式间距 -->  <div class="p-4 md:p-6 lg:p-8">内容</div></template>

自定义断点

// tailwind.config.jsexport default {  theme: {    screens: {      xs: "375px", // 小手机      sm: "640px",      md: "768px",      lg: "1024px",      xl: "1280px",    },  },};

vw 适配(移动端 H5)

对于纯移动端 H5 页面,vw 适配是最简单的方案:

/* 以 375px 设计稿为基准 *//* 1vw = 3.75px,100vw = 375px */.container {  width: 100vw;  padding: 4vw; /* 15px */}.title {  font-size: 4.8vw; /* 18px */}.button {  height: 12vw; /* 45px */  font-size: 3.73vw; /* 14px */}

用 PostCSS 插件自动转换(推荐):

pnpm add -D postcss-px-to-viewport-8-plugin
// postcss.config.jsexport default {  plugins: {    "postcss-px-to-viewport-8-plugin": {      viewportWidth: 375, // 设计稿宽度      unitPrecision: 5,      viewportUnit: "vw",      selectorBlackList: [".ignore", ".hairlines"],      minPixelValue: 1,      mediaQuery: false,    },  },};

配置后,直接写 px,自动转换为 vw:

/* 写 px */.button {  height: 45px;  font-size: 14px;}/* 自动转换为 vw */.button {  height: 12vw;  font-size: 3.73333vw;}

useBreakpoints 检测屏幕尺寸

// composables/useBreakpoints.tsimport { useBreakpoints as vueUseBreakpoints } from "@vueuse/core";const breakpoints = vueUseBreakpoints({  xs: 375,  sm: 640,  md: 768,  lg: 1024,  xl: 1280,});export function useBreakpoints() {  return {    isMobile: breakpoints.smaller("md"),    isTablet: breakpoints.between("md", "lg"),    isDesktop: breakpoints.greaterOrEqual("lg"),    current: breakpoints.active(),  };}
<script setup>  import { useBreakpoints } from "@/composables/useBreakpoints";  const { isMobile, isDesktop } = useBreakpoints();</script><template>  <!-- 根据屏幕尺寸渲染不同组件 -->  <MobileNav v-if="isMobile" />  <DesktopNav v-else />  <!-- 移动端显示简化版,PC 显示完整版 -->  <SimpleTable v-if="isMobile" :data="data" />  <FullTable v-else :data="data" :columns="columns" /></template>

常见移动端坑点

1. 安全区域(刘海屏)

/* 处理 iPhone 刘海和底部 Home 条 */.header {  padding-top: env(safe-area-inset-top);}.footer {  padding-bottom: env(safe-area-inset-bottom);}/* Tailwind 写法 */
<template>  <div class="pb-safe">    <!-- pb-safe 需要配置 Tailwind 插件 -->  </div></template>

2. 1px 边框

/* 移动端 1px 边框(高清屏显示 2px 问题) */.border-1px {  position: relative;}.border-1px::after {  content: "";  position: absolute;  left: 0;  bottom: 0;  width: 100%;  height: 1px;  background: #e2e8f0;  transform: scaleY(0.5);  transform-origin: 0 100%;}

3. 点击延迟(300ms)

/* 消除移动端点击 300ms 延迟 */* {  touch-action: manipulation;}

4. 禁止文字选中

/* 按钮等交互元素禁止文字选中 */.btn,.nav-item {  user-select: none;  -webkit-user-select: none;}

5. 滚动优化

/* 移动端流畅滚动 */.scroll-container {  overflow-y: auto;  -webkit-overflow-scrolling: touch;  overscroll-behavior: contain; /* 防止滚动穿透 */}

6. 输入框被键盘遮挡

// 监听键盘弹出,滚动到输入框function handleFocus(event: FocusEvent) {  const input = event.target as HTMLElement;  setTimeout(() => {    input.scrollIntoView({ behavior: "smooth", block: "center" });  }, 300);}

响应式图片

<template>  <!-- 不同屏幕加载不同尺寸的图片 -->  <picture>    <source media="(min-width: 1024px)" srcset="/images/hero-lg.jpg" />    <source media="(min-width: 768px)" srcset="/images/hero-md.jpg" />    <img src="/images/hero-sm.jpg" alt="Hero" />  </picture>  <!-- 或者用 Nuxt Image -->  <NuxtImg    src="/images/hero.jpg"    sizes="100vw sm:50vw md:400px"    format="webp"  /></template>

写在最后

移动端适配没有银弹,选对方案很重要:

  • • PC + 移动端兼容:Tailwind 响应式断点,最简洁
  • • 纯移动端 H5:vw 适配 + PostCSS 自动转换
  • • 需要 JS 判断屏幕:VueUse 的 useBreakpoints

#Vue响应式布局 #移动端适配 #Tailwind响应式 #vw适配 #useBreakpoints #Vue3