vue移动端开发兼容与适配

1,796 阅读3分钟

vue移动端相较于web端开发,更难应该就是适配各种不同屏幕宽度的机型以及对安卓和ios系统的兼容性问题。

适配各种机型

几种常见机型的宽度:

iPhone 6/7/8/X 375

iPhone 5/5E 320

iPad 768

一般UI设计稿都是按照375像素给的

适配也有好几种方法,如使用vh/vw,或者是rem,现在最方便的便是使用阿里团队开源的库flexible.js,实现了rem自适应。

flexible.js

const lib = window.lib || (window.lib = {})
const doc = window.document
const docEl = doc.documentElement
let metaEl = doc.querySelector('meta[name="viewport"]')
const flexibleEl = doc.querySelector('meta[name="flexible"]')
let dpr = 0
let scale = 0
let tid
const flexible = lib.flexible || (lib.flexible = {})

if (metaEl) {
  const match = metaEl.getAttribute('content').match(/initial-scale=([\d.]+)/)
  if (match) {
    scale = parseFloat(match[1])
    dpr = parseInt(1 / scale)
  }
} else if (flexibleEl) {
  const content = flexibleEl.getAttribute('content')
  if (content) {
    const initialDpr = content.match(/initial-dpr=([\d.]+)/)
    const maximumDpr = content.match(/maximum-dpr=([\d.]+)/)
    if (initialDpr) {
      dpr = parseFloat(initialDpr[1])
      scale = parseFloat((1 / dpr).toFixed(2))
    }
    if (maximumDpr) {
      dpr = parseFloat(maximumDpr[1])
      scale = parseFloat((1 / dpr).toFixed(2))
    }
  }
}

if (!dpr && !scale) {
  const isIPhone = window.navigator.appVersion.match(/iphone/gi)
  const devicePixelRatio = window.devicePixelRatio
  if (isIPhone) {
    // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
    if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
      dpr = 3
    } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
      dpr = 2
    } else {
      dpr = 1
    }
  } else {
    // 其他设备下,仍旧使用1倍的方案
    dpr = 1
  }
  scale = 1 / dpr
}

docEl.setAttribute('data-dpr', dpr)
if (!metaEl) {
  metaEl = doc.createElement('meta')
  metaEl.setAttribute('name', 'viewport')
  metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no')
  if (docEl.firstElementChild) {
    docEl.firstElementChild.appendChild(metaEl)
  } else {
    const wrap = doc.createElement('div')
    wrap.appendChild(metaEl)
    doc.write(wrap.innerHTML)
  }
}

function refreshRem () {
  let width = docEl.getBoundingClientRect().width
  if (width / dpr > 540) {
    width = width * dpr
  }
  const rem = width / 10
  docEl.style.fontSize = rem + 'px'
  window.rem = rem
  flexible.rem = window.rem
}

window.addEventListener('resize', function () {
  clearTimeout(tid)
  tid = setTimeout(refreshRem, 300)
}, false)
window.addEventListener('pageshow', function (e) {
  if (e.persisted) {
    clearTimeout(tid)
    tid = setTimeout(refreshRem, 300)
  }
}, false)

if (doc.readyState === 'complete') {
  doc.body.style.fontSize = 12 * dpr + 'px'
} else {
  doc.addEventListener('DOMContentLoaded', function (e) {
    doc.body.style.fontSize = 12 * dpr + 'px'
  }, false)
}

refreshRem()
window.dpr = dpr
flexible.dpr = window.dpr
flexible.refreshRem = refreshRem
flexible.rem2px = function (d) {
  let val = parseFloat(d) * this.rem
  if (typeof d === 'string' && d.match(/rem$/)) {
    val += 'px'
  }
  return val
}
flexible.px2rem = function (d) {
  let val = parseFloat(d) / this.rem
  if (typeof d === 'string' && d.match(/px$/)) {
    val += 'rem'
  }
  return val
}

尽管这样,我们对一些默认单位是px的配置就无法达到适配效果,比如使用echarts组件对一些字号的配置,默认单位是px,这时候需要单独对数据进行相应比例的调整(以375屏幕为例):

// 自适应字体大小
function fontSize (res) {
  const clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
  if (!clientWidth) return
  const fontSize = 100 * (clientWidth / 375)
  return res * fontSize
}

解决了适配的问题,但是却出现了很多ios上出现的bug而安卓却是正常的。

这就是大概为什么说ios在移动端就相当于web端的IE浏览器,都是程序员的噩梦。😂

ios出现的bug

  1. ios的input点击时会放大

解决方法:

<meta content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, width=device-width" name="viewport">

initial-scale初始化缩放比例,maximum-scale允许用户缩放的最大比例,minimum-scale允许用户缩放的最小比例,user-scalable是否允许用户缩放

  1. ios点击时出现阴影

解决方法:

-webkit-tap-highlight-color: rgba(255,255,255,0)
  1. ios渐变有transparent时会变为灰色,安卓正常

解决方法:

将transparent改为rgba(255,255,255,0)

  1. ios translate,transition出现闪屏现象,例如当你用作动画效果时,发现ios下每一次动画都会出现屏幕闪一下,而安卓正常

解决方法: 这里我采用的时将元素绝定位,脱离文档流,通过控制元素的left(right/top/bottom)实现相同的效果. 当然还有另一种方法: ios transition translate闪屏问题总结

感谢以下文章的作者:

移动web在ios和android下点击元素出现阴影问题

ios transition translate闪屏问题总结