阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Vue3移动端解决方案

Vue3移动端解决方案

作者:陈川 阅读数:65036人阅读 分类: Vue.js

Vue3移动端适配方案

移动端开发需要考虑屏幕尺寸、设备像素比、触摸交互等因素。Vue3提供了多种方案来解决移动端适配问题,下面介绍几种主流方案。

视口单位适配

使用vw/vh单位可以很好地实现移动端适配:

/* 基准尺寸375px设计稿 */
html {
  font-size: calc(100vw / 3.75);
}

.box {
  width: 1rem; /* 相当于设计稿中的37.5px */
  height: 0.8rem;
  font-size: 0.28rem;
}

配合postcss-px-to-viewport插件可以自动转换px单位:

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-px-to-viewport': {
      viewportWidth: 375,
      unitPrecision: 5,
      viewportUnit: 'vw',
      selectorBlackList: [],
      minPixelValue: 1,
      mediaQuery: false
    }
  }
}

弹性布局方案

Flex布局是移动端最常用的布局方式:

<template>
  <div class="container">
    <div class="header">头部</div>
    <div class="content">
      <div v-for="item in 5" :key="item" class="item">项目{{item}}</div>
    </div>
    <div class="footer">底部</div>
  </div>
</template>

<style scoped>
.container {
  display: flex;
  flex-direction: column;
  height: 100vh;
}
.header, .footer {
  flex: 0 0 50px;
}
.content {
  flex: 1;
  display: flex;
  flex-wrap: wrap;
}
.item {
  flex: 0 0 50%;
  height: 100px;
}
</style>

移动端组件库

Vant是优秀的Vue3移动端组件库:

npm install vant@next

全局引入:

import { createApp } from 'vue'
import Vant from 'vant'
import 'vant/lib/index.css'

const app = createApp(App)
app.use(Vant)

按需引入示例:

<template>
  <van-button type="primary">主要按钮</van-button>
  <van-cell-group>
    <van-field v-model="value" label="文本" placeholder="请输入文本" />
  </van-cell-group>
</template>

<script setup>
import { ref } from 'vue'
import { Button as VanButton, CellGroup as VanCellGroup, Field as VanField } from 'vant'

const value = ref('')
</script>

手势处理

Vue3可以使用@vueuse/gesture处理复杂手势:

npm install @vueuse/gesture

示例代码:

<template>
  <div 
    ref="boxRef"
    style="width: 100px; height: 100px; background: red"
    @tap="onTap"
    @pan="onPan"
  ></div>
</template>

<script setup>
import { ref } from 'vue'
import { useGesture } from '@vueuse/gesture'

const boxRef = ref(null)
const onTap = () => console.log('tap')
const onPan = (state) => {
  console.log(state.movement) // [x, y] 移动距离
}

useGesture({
  onTap,
  onPan
}, {
  target: boxRef,
  eventOptions: { passive: true }
})
</script>

性能优化

移动端需要特别注意性能优化:

  1. 图片懒加载
<template>
  <img v-lazy="imgUrl" alt="">
</template>

<script setup>
import { Lazyload } from 'vant'
app.use(Lazyload)
</script>
  1. 虚拟列表优化长列表
<template>
  <van-list
    v-model:loading="loading"
    :finished="finished"
    @load="onLoad"
  >
    <div v-for="item in list" :key="item">{{ item }}</div>
  </van-list>
</template>
  1. 使用keep-alive缓存组件
<router-view v-slot="{ Component }">
  <keep-alive>
    <component :is="Component" />
  </keep-alive>
</router-view>

移动端调试

Chrome DevTools远程调试:

  1. 手机开启USB调试
  2. Chrome访问chrome://inspect
  3. 选择设备进行调试

VConsole方案:

npm install vconsole
import VConsole from 'vconsole'
new VConsole()

PWA支持

Vue3项目添加PWA支持:

npm install @vitejs/plugin-pwa

vite配置:

import { VitePWA } from 'vite-plugin-pwa'

export default defineConfig({
  plugins: [
    VitePWA({
      includeAssets: ['favicon.ico'],
      manifest: {
        name: 'My App',
        short_name: 'App',
        theme_color: '#ffffff',
        icons: [
          {
            src: 'pwa-192x192.png',
            sizes: '192x192',
            type: 'image/png'
          }
        ]
      }
    })
  ]
})

跨端开发方案

使用uni-app跨端开发:

npm install -g @vue/cli
vue create -p dcloudio/uni-preset-vue my-project

示例页面:

<template>
  <view class="container">
    <text>Hello uni-app</text>
    <button @click="onClick">点击</button>
  </view>
</template>

<script setup>
const onClick = () => {
  uni.showToast({
    title: '点击了按钮'
  })
}
</script>

<style>
.container {
  padding: 20px;
}
</style>

状态管理方案

Pinia在移动端的应用:

npm install pinia

创建store:

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    }
  }
})

组件中使用:

<template>
  <div>{{ counter.count }}</div>
  <button @click="counter.increment()">+</button>
</template>

<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>

动画处理

Vue3过渡动画在移动端的应用:

<template>
  <button @click="show = !show">切换</button>
  <transition name="fade">
    <div v-if="show" class="box"></div>
  </transition>
</template>

<style>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
.box {
  width: 100px;
  height: 100px;
  background: red;
}
</style>

使用GSAP实现复杂动画:

npm install gsap
<script setup>
import { ref, onMounted } from 'vue'
import gsap from 'gsap'

const boxRef = ref(null)
onMounted(() => {
  gsap.to(boxRef.value, {
    x: 100,
    duration: 1,
    repeat: -1,
    yoyo: true
  })
})
</script>

移动端路由处理

Vue Router在移动端的特殊处理:

const router = createRouter({
  history: createWebHashHistory(), // 移动端推荐hash模式
  routes: [
    {
      path: '/',
      component: Home,
      meta: {
        keepAlive: true // 需要缓存的页面
      }
    }
  ],
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return savedPosition
    } else {
      return { top: 0 }
    }
  }
})

页面切换动画:

<router-view v-slot="{ Component }">
  <transition name="slide">
    <component :is="Component" />
  </transition>
</router-view>

<style>
.slide-enter-active,
.slide-leave-active {
  transition: transform 0.3s ease;
}
.slide-enter-from {
  transform: translateX(100%);
}
.slide-leave-to {
  transform: translateX(-30%);
}
</style>

移动端安全区域处理

处理iPhone等设备的刘海屏:

.safe-area {
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

使用postcss-env插件自动添加:

// postcss.config.js
module.exports = {
  plugins: {
    'postcss-env': {
      browsers: 'last 2 versions'
    }
  }
}

移动端主题切换

实现暗黑模式:

<template>
  <button @click="toggleDark">切换主题</button>
</template>

<script setup>
import { useDark, useToggle } from '@vueuse/core'

const isDark = useDark()
const toggleDark = useToggle(isDark)
</script>

<style>
.dark {
  background: #222;
  color: white;
}
</style>

移动端本地存储

使用Pinia持久化存储:

npm install pinia-plugin-persistedstate

配置:

import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)

在store中使用:

export const useUserStore = defineStore('user', {
  state: () => ({
    token: ''
  }),
  persist: true
})

移动端API请求封装

封装axios请求:

// utils/request.js
import axios from 'axios'

const service = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

service.interceptors.request.use(config => {
  config.headers['X-Token'] = getToken()
  return config
})

service.interceptors.response.use(
  response => {
    return response.data
  },
  error => {
    return Promise.reject(error)
  }
)

export default service

组件中使用:

<script setup>
import request from '@/utils/request'
import { ref } from 'vue'

const list = ref([])
request.get('/api/list').then(res => {
  list.value = res.data
})
</script>

移动端WebSocket通信

实现实时通信:

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'

const messages = ref([])
let socket = null

onMounted(() => {
  socket = new WebSocket('wss://echo.websocket.org')
  
  socket.onopen = () => {
    socket.send('Hello Server!')
  }
  
  socket.onmessage = (e) => {
    messages.value.push(e.data)
  }
})

onUnmounted(() => {
  socket?.close()
})
</script>

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:Vue3与Electron集成

下一篇:Vue3微前端方案

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌