likes
comments
collection
share

【Vue3】如何一个项目实现PC/移动端的多端适配

作者站长头像
站长
· 阅读数 14

写在前面:

什么是多端适配?

前端的多端适配是指在开发前端网页或应用程序时,通过编写不同的布局和样式代码,使得同一个项目能够适应不同的终端设备,如PC端和移动端,以提供更好的用户体验。 由于PC端和移动端的屏幕尺寸、分辨率、交互方式等存在差异,为了使网页或应用程序在不同设备上都能正常显示和使用,需要进行多端适配。

效果如下:

【Vue3】如何一个项目实现PC/移动端的多端适配

实现步骤:

1.判断客户端是否为移动端设备

首先,创建一个工具类js,用于存放相关判断函数 创建isWap以及isWapPage函数,用于检测当前设备是否为移动端设备

1.函数 isWap 定义一个变量 userAgentInfo,它保存了浏览器的用户代理信息。然后,定义一个包含各种移动设备名称的数组 Agents。变量 flag 被初始化为 true,用于标记当前设备是否为移动设备。

接下来,通过遍历 Agents 数组,检查用户代理信息中是否包含其中任何一个移动设备的名称。如果包含,说明当前设备是移动设备,将 flag 设置为 false 并跳出循环。

在 flag 为 true 的情况下,通过获取页面可视区域的宽度,判断当前设备是否为移动设备。如果宽度小于 840 像素,则被判定为手机设备,将 flag 设置为 false

最后返回 !flag,即返回当前设备是否为移动设备的布尔值。

2.函数 isWapPage 用于检测当前页面是否是移动端页面。首先创建一个空数组 routerNames,然后定义了一个递归函数 getAllRouterNames,用于遍历 routers 数组并将路由名称存储在 routerNames 中。

接着通过 window.location.href 获取当前页面的 URL,并使用 split('#')[1] 获取 URL 中的路径部分。然后,使用 router.resolve(path) 解析路径对应的路由信息,将结果保存在 curRoute 变量中。

最后判断 isWap() 是否为 true,以及当前路由名称是否包含 -wap 或者在 routerNames 中是否存在当前路由名称加上 -wap 的形式,来确定当前页面是否是移动端页面。如果是,则返回 true,否则返回 false。 代码如下:

export const isWap = () => {
  var userAgentInfo = navigator.userAgent
  var Agents = [
    'Android',
    'iPhone',
    'SymbianOS',
    'Windows Phone',
    'iPad',
    'iPod'
  ]
  var flag = true
  for (var v = 0; v < Agents.length; v++) {
    if (userAgentInfo.indexOf(Agents[v]) > 0) {
      flag = false
      break
    }
  }

  if (flag) {
    let width =
      document.documentElement.clientWidth || document.body.clientWidth
    if (width < 840) {
      //小于840px的屏幕,判定为手机
      flag = false
    }
  }
  return !flag
}

/** 当前url是否对应的wap页面 */
export const isWapPage = () => {
  const routerNames = []
  const getAllRouterNames = array => {
    array.forEach(element => {
      routerNames.push(element.name)
      if (element.children?.length) {
        getAllRouterNames(element.children)
      }
    })
  }
  getAllRouterNames(routers)

  const path = window.location.href.split('#')[1]
  const curRoute = router.resolve(path)

  if (
    isWap() &&
    ((curRoute.name.indexOf('-wap') < 0 &&
      routerNames.includes(curRoute.name + '-wap')) ||
      curRoute.name.indexOf('-wap') >= 0)
  ) {
    return true
  } else {
    return false
  }
}

2.判断是否为刘海屏并对iphone进行刘海屏优化

创建几个判断函数:

  • 1.函数 judgeClient 用于判断客户端类型,即判断当前设备是 Android、iOS 还是 PC。首先获取浏览器的用户代理信息,并根据用户代理信息中是否包含关键字 "Android" 或 "Adr" 来判断是否是 Android 终端。然后使用正则表达式匹配用户代理信息,判断是否是 iOS 终端。最后,根据判断结果返回相应的客户端类型。

  • 2.函数 isiPhoneX 用于判断当前设备是否是刘海屏(iPhone X 及其后续型号)。它通过调用 judgeClient 函数获取客户端类型,并根据一系列判断条件来确定是否是刘海屏设备。判断条件涉及设备的屏幕高度和宽度与特定型号的对比。

  • 3.函数 safeBottomHeight 返回一个安全区域底部高度,用于适配刘海屏设备。如果当前设备是刘海屏(通过调用 isiPhoneX 函数判断),则返回 44;否则返回 0。

  • 4.函数 safeTopHeight 返回一个安全区域顶部高度,用于适配刘海屏设备。如果当前设备是刘海屏(通过调用 isiPhoneX 函数判断),则返回 22;否则返回 0。

  • 5.函数 statusBarHeight 返回一个状态栏高度,根据客户端类型和是否是刘海屏来确定。如果客户端类型是 iOS 并且是刘海屏设备(通过调用 judgeClient 和 isiPhoneX 函数判断),则返回 44;否则返回 20。

通过以上配置即可实现刘海屏iphone移动端页面适配,如果只适配移动端不专门进行优化这一步可以忽略 代码如下:

/** 判断客户端:Android,IOS,PC */
export const judgeClient = () => {
  let u = navigator.userAgent
  let isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1 //判断是否是 android终端
  let isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) //判断是否是 iOS终端
  if (isAndroid) {
    return 'Android'
  } else if (isIOS) {
    return 'IOS'
  } else {
    return 'PC'
  }
}

/** 是否是刘海屏 */
export const isiPhoneX = () => {
  return (
    (judgeClient() === 'IOS' &&
      ((D_HEIGHT === X_HEIGHT && D_WIDTH === X_WIDTH) ||
        (D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT))) ||
    (D_HEIGHT === XSMAX_HEIGHT && D_WIDTH === XSMAX_WIDTH) ||
    (D_HEIGHT === XSMAX_WIDTH && D_WIDTH === XSMAX_HEIGHT) ||
    (D_HEIGHT === p12_HEIGHT && D_WIDTH === p12_WIDTH) ||
    (D_HEIGHT === p12_WIDTH && D_WIDTH === p12_HEIGHT) ||
    (D_HEIGHT === p12_MAX_HEIGHT && D_WIDTH === p12_MAX_WIDTH) ||
    (D_HEIGHT === p12_MAX_WIDTH && D_WIDTH === p12_MAX_HEIGHT)
  )
}

export const safeBottomHeight = () => {
  return isiPhoneX() ? 44 : 0
}

export const safeTopHeight = () => {
  return isiPhoneX() ? 22 : 0
}

export const statusBarHeight = () => {
  return judgeClient() === 'IOS' ? (isiPhoneX() ? 44 : 20) : 0
}

3.全局引入isWapPage

main.js中添加以下代码:

import { isWapPage } from './utils/index'
import './wap'

const wap = isWapPage()


if (wap) {
  app = createApp(WapApp)
  app.use(Vant)
} else {
  app = createApp(App)
  app.use(Antd)
}

4.配置全局前置路由守卫,不同设备将打开不同的页面

1.在路由index.js中,创建三个判断函数用于判断是否需要跳转到移动端页面或 PC 端页面。

函数 existWapPage 接收一个路由名称 routeName,它的作用是检查是否存在对应的移动端页面。首先创建一个空数组 routerNames,然后定义了一个递归函数 getAllRouterNames,用于遍历 routers 数组并将路由名称存储在 routerNames 中。最后,通过判断 routerNames 是否包含 routeName + '-wap',来确定是否存在对应的移动端页面,并返回相应的布尔值。

函数 needJumpToWap 接收一个路由名称 routeName,它判断是否需要跳转到移动端页面。首先通过调用 isWap() 函数判断当前设备是否为移动设备。如果是移动设备,并且 routeName 中不包含 -wap,并且存在对应的移动端页面(通过调用 existWapPage(routeName) 函数判断),则返回 true,否则返回 false

函数 needJumpToPC 接收一个路由名称 routeName,它判断是否需要跳转到 PC 端页面。首先通过调用 isWap() 函数判断当前设备是否为移动设备。如果不是移动设备,并且 routeName 中包含 -wap,则返回 true,否则返回 false

这些函数的目的是根据当前设备和路由名称,判断是否需要进行页面跳转,以适配不同的设备类型。

const existWapPage = routeName => {
  const routerNames = []
  const getAllRouterNames = array => {
    array.forEach(element => {
      routerNames.push(element.name)
      if (element.children?.length) {
        getAllRouterNames(element.children)
      }
    })
  }
  getAllRouterNames(routers)

  return routerNames.includes(routeName + '-wap')
}

const needJumpToWap = routeName => {
  if (isWap() && routeName.indexOf('-wap') < 0 && existWapPage(routeName)) {
    return true
  } else {
    return false
  }
}

const needJumpToPC = routeName => {
  if (!isWap() && routeName.indexOf('-wap') >= 0) {
    return true
  } else {
    return false
  }
}

2.配置全局前置路由守卫:

代码如下:

在这段代码中,通过这个钩子函数来处理不同设备之间的页面跳转逻辑。

  • 首先,执行了一些初始化操作,然后进行设备判断和处理wap跳转PC、PC跳转wap的逻辑。
  • 如果当前设备不是移动设备,并且路由名为 "approval-dap" 或 "approval-dap-wap",则根据不同的条件进行页面跳转。
  • 如果当前设备是移动设备,并且路由参数中的 appId 为 "2",applyType 为 "21",则进行相应的页面跳转。
  • 如果满足 needJumpToWap(to.name) 的条件,表示需要跳转至移动端页面,则执行相应的跳转逻辑。
  • 如果满足 needJumpToPC(to.name) 的条件,表示需要跳转至PC端页面,则执行相应的跳转逻辑。
  • 如果以上条件都不满足,则执行其他逻辑,并进行下一步路由导航。

5.编写移动端/PC端两套代码

至此,已经完成了一个项对PC/移动端进行多端适配,并显示两套不同的页面,只需要将pc端以及移动端页面分开存放,进行路由跳转即可。