移动端H5相关问题汇总
- 自适应问题
- iOS 滑动不流畅
- iOS 上拉边界下拉出现白色空白
- 页面件放大或缩小不确定性行为
- click 点击穿透与延迟
- 软键盘弹出将页面顶起来、收起未回落问题
- iPhone X 底部栏适配问题
- H5 调试相关方案与策略
- H5 调用 SDK 相关问题及解决方案
移动端 H5 相关基础技术概览
1、自适应问题
对于开发h5来说肯定要考虑到自适应问题,目前来说大多数的解决方法都是将px转化为rem,当然也可以使用vh,vw单位,但是个人觉得使用rem是最好的解决方案。
- 使用postcss-pxtorem
postcss-pxtorem是PostCSS的插件,用于将像素单元生成rem单位。
1.安装依赖
npm install postcss-pxtorem -D
2.设置规则(更改postcss.config.js,该文件为使用vue-cli3自动创建的文件)
module.exports = {
plugins: {
'autoprefixer': {
browsers: ['Android >= 4.0', 'iOS >= 7']
},
'postcss-pxtorem': {
rootValue: 16,//结果为:设计稿元素尺寸/16,比如元素宽320px,最终页面会换算成 20rem
propList: ['*']
}
}
}
- 设置最顶层父级font-size,所有单位使用rem
* 基于iphone375宽度的基准做制作,把body的font-size按比例设置成约等于10px
* 设置字体大小用单位em 1em=10px,1.4em=14px....以此类推
* @type {string}
*/
// document.getElementsByTagName("body")[0].style.fontSize = document.body.clientWidth / 37.5 + 'px';
if (document.documentElement.clientWidth > 640) {
document.documentElement.style.fontSize =
640 / 3.75 / 2 + 'px'
} else {
document.documentElement.style.fontSize =
document.documentElement.clientWidth / 3.75 / 2 + 'px'
}
2、iOS 滑动不流畅
问题描述:上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。
原因:原来在 iOS 5.0 以及之后的版本,滑动有定义有两个值 auto 和 touch,默认值为 auto。
-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
-webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */
解决方法:
.wrapper {
-webkit-overflow-scrolling: touch;
}
body {
overflow-y: hidden;
}
.wrapper {
overflow-y: auto;
}
// 设置滚动条隐藏: .container ::-webkit-scrollbar {display: none;}
3、iOS 上拉边界下拉出现白色空白
问题描述: 手指按住屏幕下拉,屏幕顶部会多出一块白色区域。手指按住屏幕上拉,底部多出一块白色区域。
原因: 在 iOS 中,手指按住屏幕上下拖动,会触发 touchmove 事件。这个事件触发的对象是整个 webview 容器,容器自然会被拖动,剩下的部分会成空白。
解决方案: 监听事件禁止滑动
1. touchstart :手指放在一个DOM元素上。
2. touchmove :手指拖曳一个DOM元素。
3. touchend :手指从一个DOM元素上移开。
document.body.addEventListener('touchmove', function(e) {
if(e._isScroller) return;
// 阻止默认事件
e.preventDefault();
}, {
passive: false
});
4、click 点击事件延时与穿透
问题描述: 监听元素 click 事件,点击元素触发时间延迟约 300ms。
点击蒙层,蒙层消失后,下层元素点击触发。
产生原因: iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。
解决方案:
1、使用 touchstart 替换 click
移动设备不仅支持点击,还支持几个触摸事件。那么我们现在基本思路就是用 touch 事件代替click 事件。
将 click 替换成 touchstart 不仅解决了 click 事件都延时问题,还解决了穿透问题。因为穿透问题是在 touch 和 click 混用时产生。
// 原生方法
el.addEventListener("touchstart", () => { console.log("ok"); }, false);
// vue方法
<button @touchstart="handleTouchstart()">点击</button>
2、使用 fastclick 库
// fastclick 库可以使click 延时和穿透问题都没了,但是需要安装依赖
// fastclick源码 核心代码不长, 1000 行不到。有兴趣可以了解一下!
import FastClick from 'fastclick';
FastClick.attach(document.body, options);
5、软键盘将页面顶起来、收起未回落问题
问题描述: Android 手机中,点击 input 框时,键盘弹出,将页面顶起来,导致页面样式错乱。
移开焦点时,键盘收起,键盘区域空白,未回落。
产生原因: 我们在app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 absolute 和 fixed 定位的元素。导致可视区域变小,布局错乱。
解决方法: 其实就是通过监听页面高度变化,强制恢复成弹出前的高度。
// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function(){
var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
if(resizeHeight < originalHeight ){
// 恢复内容区域高度
// const container = document.getElementById("container")
// 例如 container.style.height = originalHeight;
}
}
键盘不能回落问题出现在 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 开发中是比较常见的 Bug。
兼容原理,1.判断版本类型 2.更改滚动的可视区域
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = (navigator.appVersion).match(/OS (\d+)_(\d+)_?(\d+)?/);
// 如果设备类型为iOS 12+ 和wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, '') >= 674 && +version[1] >= 12) {
window.scrollTo(0, Math.max(document.body.clientHeight, document.documentElement.clientHeight));
}
// window.scrollTo(x-coord, y-coord),其中window.scrollTo(0, clientHeight)恢复成原来的视口
6、iPhone X系列安全区域适配问题
问题描述: 头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。
产生原因: iPhone X 以及它以上的系列,都采用刘海屏设计和全面屏手势。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。
解决方法:
1、设置安全区域,填充危险区域,危险区域不做操作和内容展示。
设置 viewport-fit 为 cover
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover">
7、页面生成为图片和二维码问题
生成二维码
使用 QRCode 生成二维码
// 在vue中实现
<template>
<div id="qrcode"
ref="qrcode"
class="scan">
</div>
</template>
import QRCode from 'qrcodejs2';
mounted () {
// setTimeout(() => {
// this.toImage()
// }, 3000);
this.$nextTick(() => {
this.qrcode();
});
},
// 生成二维码
qrcode () {
let qrcode = new QRCode('qrcode', {
width: 188, // 二维码宽度,单位像素
height: 192, // 二维码高度,单位像素
text: this.resp.url // 生成二维码的链接
});
},
生成图片
生成图片的在之前的博客上有,大家可以翻一翻
8、微信公众号分享问题
问题描述: 在微信公众号 H5 开发中,页面内部点击分享按钮调用 SDK,方法不生效。
解决方法: 添加一层蒙层,做分享引导。
9、H5 调用 SDK 相关解决方案
产生原因: 在 Hybrid App 中使用 H5 是最常见的不过了,刚接触的,肯定会很生疏模糊。不知道 H5 和 Hybrid 是怎么交互的。怎样同时支持 iOS 和 Android 呢?现在来谈谈 Hybrid 技术要点,原生与 H5 的通信。
解决方案: 使用 DSBridge 同时支持 iOS 与 Android
SDK小组 提供方法:
1、注册方法 bridge.register
bridge.register('enterApp', function() {
broadcast.emit('ENTER_APP')
})
2、回调方法 bridge.call
export const getSDKVersion = () => bridge.call('BLT.getSDKVersion')
3、事件监听与触发法
const broadcast = {
on: function(name, fn, pluralable) {
this._on(name, fn, pluralable, false)
},
once: function(name, fn, pluralable) {
this._on(name, fn, pluralable, true)
},
_on: function(name, fn, pluralable, once) {
let eventData = broadcast.data
let fnObj = { fn: fn, once: once }
if (pluralable && Object.prototype.hasOwnProperty.call(eventData, 'name')) {
eventData[name].push(fnObj)
} else {
eventData[name] = [fnObj]
}
return this
},
emit: function(name, data, thisArg) {
let fn, fnList, i, len
thisArg = thisArg || null
fnList = broadcast.data[name] || []
for (i = 0, len = fnList.length; i < len; i++) {
fn = fnList[i].fn
fn.apply(thisArg, [data, name])
if (fnList[i].once) {
fnList.splice(i, 1)
i--
len--
}
}
return this
},
data: {}
}
export default broadcast
踩坑注意
方法调用前,一定要判断 SDK 是否提供该方法 如果 Android 提供该方法,iOS 上调用就会出现一个方法调用失败等弹窗。怎么解决呢?
提供一个判断是否 Android、iOS。根据设备进行判断
export const hasNativeMethod = (name) =>
return bridge.hasNativeMethod('BYJ.' + name)
}
export const getSDKVersion = function() {
if (hasNativeMethod('getSDKVersion')) {
bridge.call('BYJ.getSDKVersion')
}
}