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
- 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是否允许用户缩放
- ios点击时出现阴影
解决方法:
-webkit-tap-highlight-color: rgba(255,255,255,0)
- ios渐变有transparent时会变为灰色,安卓正常
解决方法:
将transparent改为rgba(255,255,255,0)
- ios translate,transition出现闪屏现象,例如当你用作动画效果时,发现ios下每一次动画都会出现屏幕闪一下,而安卓正常
解决方法: 这里我采用的时将元素绝定位,脱离文档流,通过控制元素的left(right/top/bottom)实现相同的效果. 当然还有另一种方法: ios transition translate闪屏问题总结
感谢以下文章的作者: