干货:开启 “ 移动端开发踩坑” 之旅

·  阅读 271

作为一个开发了多个 H5 项目的前端工程师,在开发过程中难免会遇到一些兼容性等爬过坑的问题。现在我将这些问题一一汇总一下,并在后面给出坑产生的原理,和现阶段常规的填坑方案。希望对前端小伙伴有所帮助。

移动端体验优化经验总结与实践(重要)

借用人人都是产品经理上面对体验的论述:当技术已不再是产品核心竞争力时,产品竞争的实质就是用户体验之争。

考虑到市面上绝大多数 APP 都是 Native+H5 相结合的应用,因此将从 Native 端和 H5 端分别总结如何优化体验。

1、Native 端体验优化

应该具备以下基本特质:

1)启动速度要快

2)交互流畅不卡顿

3)有离线缓存

4)支持弱网环境

5)友好的用户提示

启动优化, 内存优化、 UI渲染优化、 网络优化等,内存和 UI 渲染的优化主要针对卡顿问题,网络优化中一个重点涉及的对象是缓存和弱网支持。

内存优化

内存的优化首先要避免大量的内存泄露,可以使用leakcanary进行自动检测,若要深入分析,可以使用 AndroidStudio 手动 dump 内存下来用MAT工具进行分析,发现其中潜在的内存泄露对象。

内存优化除了注意 内存泄露,还要关注 内存的抖动,出现的原因一般是大量频繁的创建对象。

UI 渲染优化

UI 渲染性能关系到 APP 的流畅度,16ms 内未能完成一次绘制就会出现掉帧,给人感觉就是页面卡顿,响应不及时。

2、H5 页面加速优化

三个方向可以进行优化:

1)页面启动白屏时间

2)H5 页面的交互体验,如响应流畅度

3)页面渲染性能

从前端的角度入手,可以有以下几个优化手段:

  • 资源压缩,前端有成熟的工具可以对生成的 js、css 等产物进行压缩,若有必要可以还考虑 gzip 压缩,获得更大的压缩比。

  • 资源请求合并,过多分散的资源包会产生过多的网络请求,但也不能随意合并,最佳的方式是按照页面或者模块进行划分,并配置 async 属性来异步加载 script 脚本。

  • 配置浏览器缓存,主要指强缓存和协商缓存,可以大大减少网络时延,减少服务器压力。

  • 按需加载,对于单页应用,如果在首页就把整个站点的资源全部下载,其实是不合理的,使用按需加载(懒加载)的方式可以有效提高首页性能。

  • 骨架屏也是在移动端页面首屏优化的一个重要手段,在页面数据未准备好的情况,相比与枯燥的白屏页面而言,展示骨架屏能给用户一个好的感官体验。但是如何生成质量高的骨架屏也是一个难点,需要综合考虑 ROI 来选择是否使用骨架屏。

一、移动端开发基础-HTML方向

1、调用系统功能-打电话\发短信\邮件

移动设备的电话/短信/邮件三大通讯功能,快速调用移动设备的的图库/文件。

<!-- 拨打电话 -->
<a href="tel:10086">拨打电话给10086小姐姐</a>

<!-- 发送短信 -->
<a href="sms:10086">发送短信给10086小姐姐</a>

<!-- 发送邮件 -->
<a href="mailto:young.joway@aliyun.com">发送邮件给JowayYoung</a>

<!-- 选择照片或拍摄照片 -->
<input type="file" accept="image/*">

<!-- 选择视频或拍摄视频 -->
<input type="file" accept="video/*">

<!-- 多选文件 -->
<input type="file" multiple>
复制代码

2、忽略自动识别(常用)

<!-- 忽略自动识别电话 -->
<meta name="format-detection" content="telephone=no">

<!-- 忽略自动识别邮箱 -->
<meta name="format-detection" content="email=no">

<!-- 忽略自动识别电话和邮箱 -->
<meta name="format-detection" content="telephone=no, email=no">
复制代码

3、弹出数字键盘(常用)

<!-- 纯数字带#和* -->
<input type="tel">

<!-- 纯数字 -->
<input type="number" pattern="\d*">
复制代码

4、禁止页面缩放(常用)

在智能手机的普及下,很多网站都具备桌面端和移动端两种浏览版本,因此无需双击缩放查看页面。禁止页面缩放可保障移动端浏览器能无遗漏地展现页面所有布局。

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, minimum-scale=1, maximum-scale=1">
复制代码

5、禁止页面缓存(常用)

「Cache-Control」指定请求和响应遵循的缓存机制,不想使用浏览器缓存就禁止呗!

<meta http-equiv="Cache-Control" content="no-cache">
复制代码

6、禁止字母大写

有时在输入框里输入文本会默认开启首字母大写纠正,就是输入首字母小写会被自动纠正成大写,特么的烦。直接声明autocapitalize=off关闭首字母大写功能和autocorrect=off关闭纠正功能。

<input autocapitalize="off" autocorrect="off">
复制代码

7、针对Safari配置

<!-- 设置Safari全屏,在iOS7+无效 -->
<meta name="apple-mobile-web-app-capable" content="yes">

<!-- 改变Safari状态栏样式,可选default/black/black-translucent,需在上述全屏模式下才有效 -->
<meta name="apple-mobile-web-app-status-bar-style" content="black">

<!-- 添加页面启动占位图 -->
<link rel="apple-touch-startup-image" href="pig.jpg" media="(device-width: 375px)">

<!-- 保存网站到桌面时添加图标 -->
<link rel="apple-touch-icon" sizes="76x76" href="pig.jpg">

<!-- 保存网站到桌面时添加图标且清除默认光泽 -->
<link rel="apple-touch-icon-precomposed" href="pig.jpg">
复制代码

二、移动端开发基础-CSS方向

1、支持弹性滚动(常用)

在苹果系统上非元素的滚动操作可能会存在卡顿,但安卓系统不会出现该情况。通过声明overflow-scrolling:touch调用系统原生滚动事件优化弹性滚动,增加页面滚动的流畅度。

body {
    -webkit-overflow-scrolling: touch;
}
.elem {
    overflow: auto;
}
复制代码

2、禁止滚动传播(基础-进阶)

与桌面端浏览器不一样,移动端浏览器有一个奇怪行为。当页面包含多个滚动区域时,滚完一个区域后若还存在滚动动量则会将这些剩余动量传播到下一个滚动区域,造成该区域也滚动起来。这种行为称为「滚动传播」。

若不想产生这种奇怪行为可直接禁止。

.elem {
    overscroll-behavior: contain;
}
复制代码

3、禁止屏幕抖动(基础-进阶)

对于一些突然出现滚动条的页面,可能会产生左右抖动的不良影响。在一个滚动容器里,打开弹窗就隐藏滚动条,关闭弹窗就显示滚动条,来回操作会让屏幕抖动起来。提前声明滚动容器的padding-right为滚动条宽度,就能有效消除这个不良影响。

每个移动端浏览器的滚动条宽度都有可能不一致,甚至不一定占位置,通过以下方式能间接计算出滚动条的宽度。100vw为视窗宽度,100%为滚动容器内容宽度,相减就是滚动条宽度,妥妥的动态计算。

body {
    padding-right: calc(100vw - 100%);
}
复制代码

4、禁止长按操作

有时不想用户长按元素呼出菜单进行点链接、打电话、发邮件、保存图片或扫描二维码等操作,声明touch-callout:none禁止用户长按操作。

有时不想用户复制粘贴盗文案,声明user-select:none禁止用户长按操作和选择复制。

* {
    /* pointer-events: none; */ /* 微信浏览器还需附加该属性才有效 */
    user-select: none; /* 禁止长按选择文字 */
    -webkit-touch-callout: none;
}
复制代码

但声明user-select:none会让和无法输入文本,可对其声明user-select:auto排除在外。

input,
textarea {
    user-select: auto;
}
复制代码

5、禁止字体调整(常用)

旋转屏幕可能会改变字体大小,声明text-size-adjust:100%让字体大小保持不变。

* {
    text-size-adjust: 100%;
}
复制代码

6、美化滚动占位

滚动条样式太丑希望自定义,::-webkit-scrollbar-*来帮你。记住以下三个关键词就能随机应变了。

  • [x] 「::-webkit-scrollbar」:滚动条整体部分

  • [x] 「::-webkit-scrollbar-track」:滚动条轨道部分

  • [x] 「::-webkit-scrollbar-thumb」:滚动条滑块部分

    ::-webkit-scrollbar { width: 6px; height: 6px; background-color: transparent; } ::-webkit-scrollbar-track { background-color: transparent; } ::-webkit-scrollbar-thumb { border-radius: 3px; background-image: linear-gradient(135deg, #09f, #3c9); }

7、识别文本换行

多数情况会使用JS换行文本,那就真的Out了。若接口返回字段包含\n或
,千万别替换掉,可声明white-space:pre-line交由浏览器做断行处理。

* {
    white-space: pre-line;
}
复制代码

8、监听屏幕旋转(基础-用户体验)

/* 竖屏 */
@media all and (orientation: portrait) {
    /* 自定义样式 */
}
/* 横屏 */
@media all and (orientation: landscape) {
    /* 自定义样式 */
}
复制代码

9、:before :after使用

( input,img,iframe等元素都不能包含其他元素,所以不能通过伪元素插入内容。)

三、常见问题(项目实践-重要)

1、H5 页面- iPhoneX 刘海屏适配

刘海屏显示

页面适配代码

1) 在为页面适配刘海屏之前,我们首先得在页面的 meta 中添加一个新的值:

<meta name="viewport" content="viewport-fit=cover">
复制代码

2) 设置高度:

//为导航栏+状态栏的高度 88px (导航栏 44px,状态栏 44px)
padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);

//为底下圆弧的高度 34px
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
复制代码

扩展:css 函数 env() 和 constant()

这两个函数都是 webkit 中 css 函数,可以直接使用变量函数,只有在 webkit 内核下才支持。

  1. env 函数:必须在 ios >= 11.2 才支持;

  2. constant 函数:必须 ios < 11.2 支持

*iOS11 新增特性,Webkit 的一个 CSS 函数,用于设获取安全区域与边界的距离,有四个预定义的变量(单位是px):

  1. safe-area-inset-left:安全区域距离左边界距离,横屏时适配;

  2. safe-area-inset-right:安全区域距离右边界距离,横屏时适配;

  3. safe-area-inset-top:安全区域距离顶部边界距离,竖屏下刘海屏为44px,iphone6系列20px,竖屏刘海适配关键;

  4. safe-area-inset-bottom:安全区域距离底部边界距离,竖屏下为34px,竖屏小黑条适配关键;

适配的核心是:通过 constant() 可以获取到非安全边距,再结合 padding 或 margin 来控制页面元素避开非安全区域。

*精确到机型做适配

// ******* 正常 ios手机 刘海屏处理 ***********/
// iphoneX、iphoneXs、iphone11 Pro
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3),
// iphone 12、iphone 12 Pro
only screen and (device-width: 390px) and (device-height: 884px) and (-webkit-device-pixel-ratio:3),
// iphone Xs Max、iphone11 Pro Max
only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio:3),
// iphone XR、iphone 11
only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio:2),
// iphone 12 Pro Max
only screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio:3){
  // 头部刘海屏设置
  .title-bar {
    padding-top: constant(safe-area-inset-top); //为导航栏+状态栏的高度 88px
    padding-top: env(safe-area-inset-top);
  }
  // 底部刘海屏设置
  .tab-bar {
    padding-bottom: constant(safe-area-inset-bottom);//为底下圆弧的高度 34px
    padding-bottom: env(safe-area-inset-bottom);
  }

}
复制代码

2、自适应-calc用于动态计算长度值

利用CSS3 函数calc()计算高度

calc() = calc(四则运算) 用于动态计算长度值。

需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% – 10px);

css3的一个新增的功能,用来指定元素的长度。 (解决撑破容器的问题)

// 中间高度自适应
.mid-set {
  top: 176px;
  bottom: 98px;
  height: calc(100vh - 314px);
}

// 个人信息 input输入框撑破问题
width:-webkit-calc(100% - 9px);    
复制代码

扩展知识:

1) viewport:可视窗口,也就是浏览器。
vw Viewport宽度, 1vw 等于viewport宽度的1%

vh Viewport高度, 1vh 等于viewport高的的1%

2) 关于height:100%和height:100vh的区别

vh就是当前屏幕可见高度的1%,也就是说

height:100vh == height:100%;

但是当元素没有内容时候,设置height:100%,该元素不会被撑开,此时高度为0,

但是设置height:100vh,该元素会被撑开屏幕高度一致。

3、禁止高亮显示(基础-常用)

产生效果:部分android系统中元素被点击时产生的边框怎么去掉

触摸元素会出现半透明灰色遮罩。

a,button,input,textarea{
	-webkit-tap-highlight-color: rgba(0,0,0,0);
	-webkit-user-modify:read-write-plaintext-only;
}
复制代码

有些机型去除不了,如小米2

对于按钮类还有个办法,不使用a或者input标签,直接用div标签。

4、美化表单外观(基础-常用)

表单元素样式太丑希望自定义,appearance:none来帮你。

button,input,select,textarea {
    appearance: none;
    /* 自定义样式 */
}
复制代码

例如:

input输入框在ios下会默认有顶部内阴影的问题,在Android平台下没有这个问题。

解决办法为input添加如下样式即可:

input[type="text"] {
  -webkit-appearance: none;
}
复制代码

5、移动端文字居中问题 垂直方向(基础-常用)

有强迫症的同学总会觉得输入框文本位置整体偏上,感觉未居中心里就痒痒的。桌面端浏览器里声明line-height等于height就能解决,但移动端浏览器里还是未能解决,需将line-height声明为normal才行。

input {
    line-height: normal;
}
复制代码

在开发过程中,发现在andriod机子上出现上下居中问题,文字偏上。

已经试过的方法:

1)line-height

2)padding

3)flex

这三种方法试过都没有效果。

lang=en时按钮文字偏上,而lang=zh时按钮文字偏下

.box{    
  display: table-cell;    
  text-align: center;    
  vertical-align: middle; 
}
复制代码

6、ios端兼容input光标高度

问题详情描述:input输入框光标,在安卓手机上显示没有问题,但是在苹果手机上当点击输入的时候,光标的高度和父盒子的高度一样。

**解决办法:**高度height和行高line-height内容用padding撑开,不要用line-height属性。

7、自动适应背景(基础-常用)

使用rem布局声明一个元素背景,多数情况会将background-size声明为cover。可能在设计图对应分辨率的移动设备下,背景会完美贴合显示,但换到其他分辨率的移动设备下就会出现左右空出1px到npx的空隙。

此时将background-size声明为100% 100%,跟随width和height的变化而变化。反正width和height都是量好的实际尺寸。

.elem {
    width: 1rem;
    height: 1rem;
    background: url("pig.jpg") no-repeat center/100% 100%;
}
复制代码

8、美化输入占位(基础-常用)

输入框占位文本太丑,::-webkit-input-placeholder来帮你。

input::-webkit-input-placeholder {
    color: #66f;
}
复制代码

9、移动端ios的 input框圆角变成直角

可是在ios下 input框仍然有圆角,

Android和PC下为直角.

border-radius: 0;
复制代码

10、禁止操作 css3属性(重要)

作用:

  1. 阻止用户的点击动作产生任何效果;

  2. 阻止缺省鼠标指针的显示;

  3. 阻止CSS里的hover和active状态的变化触发事件;

  4. 阻止JavaScript点击动作触发的事件;

    pointer-events:none;

11、oninput事件,实时验证

1)大部分手机输入英文和单个汉字时会按这个顺序依次执行一遍,输入多个汉字时只执行一次input事件。测试机(小米3,联想,广信s5),点击特殊键回车或前往 也会执行keydown,keypress,keyup

2)三星的比较特殊,点击任何键都有两次keydown 两次keyup一次input

结论:

1.keyup在输入多个汉字时不执行

2.特殊键时没必要执行keyup

3.三星会执行多次keyup

改进事件:用oninput事件

参考:多看网页版和wap版用的input事件,腾讯wap版无此功能。

另外,onchange事件排除,这个事件只有在失去焦点时才执行。

例如:

文本框实时统计字数

keydown事件和onchange事件来做

onchange事件必须在表单失去焦点时才触发,无法做到实时统计;

keydown似乎能够满足要求,但是当你用鼠标复制粘贴的时候会发现字数改变了,但事件没有监听到,存在一定的漏洞。

12、开启GPU硬件加速(基础-常用)

GPU(Graphic Processing Unit,图形处理器)。GPU是相对于CPU的一个概念,由于在现代的计算机中图形的处理变得越来越重要,需要一个专门的图形的核心处理器。在浏览器中用css开启硬件加速,使GPU发挥功能。

硬件加速(*)

webkit-transform: translateZ(0);
webkit-transform: translate3d(0,0,0);
复制代码

这两个属性都会开启GPU硬件加速模式,从而让浏览器在渲染动画时从CPU转向GPU 。

页面优化方案:(重要)

1、硬件加速

2、交互太复杂

3、整合图片, 整合css,js

4、服务器启动Gzip压缩

5、最好的建议是,删场景,删内容

注:提高网页性能,就是要降低"重排(结构)"和"重绘(样式)"的频率和成本,尽量少触发重新渲染。

通过-webkit-transform:transition3d/translateZ开启GPU硬件加速的适用范围:

1、使用很多大尺寸图片(尤其是PNG24图)进行动画的页面。

2、页面有很多大尺寸图片并且进行了css缩放处理,页面可以滚动时。

3、使用background-size:cover设置大尺寸背景图,并且页面可以滚动时。

4、编写大量DOM元素进行CSS3动画时(transition/transform/keyframes/absTop&Left)

5、使用很多PNG图片拼接成CSS Sprite时。

13、拍照取相册 accept="image/*(重要)

<input type="file" accept="image/*" capture="camera">
<input type="file" accept="video/*" capture="camcorder">
<input type="file" accept="audio/*" capture="microphone">
复制代码

capture表示,可以捕获到系统默认的设备,比如:camera--照相机;camcorder--摄像机;microphone--录音。

14、多背景效果

background:url(../img/logo.png) no-repeat 20px 40px,
url(../img/bg1.jpg) no-repeat center;
background-size:107px auto,cover;
复制代码

15、1像素问题-预编译sass(常用)

@mixin border-1px($color) {
	&::after {
    content: '';
		display : block;
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: $color;
    transform: scaleY(0.5);
	}
}

// 1像素 使用 @include border-1px(#ddd);
复制代码

16、控制溢出文本-预编译sass(常用)

@mixin ellipsis($line) {
  display: -webkit-box;
  -webkit-box-orient:vertical;
  overflow: hidden;
  -webkit-line-clamp: $line;
}

// 超出省略号 使用 @include ellipsis(1);
复制代码

17、需要深入-iframe的滚动条无法拖动的bug(签协议)

<div class="signatureContet" id="signatureContet" :style="'height:' + wrapperHeight + 'px'">

mounted() {
    this.timeInit = setTimeout(() => {
      this.wrapperHeight =
        this.mode == 2 ? window.innerHeight - 40 : window.innerHeight - 40 - 44;
      this.clientWidth = window.innerWidth;
      this.clientHeight = window.innerHeight;
      document.getElementById("myIframe").style.height =
        document.getElementById("myIframe").contentDocument.body.offsetHeight +
        100 +
        "px";
    }, 200);
}
复制代码

iframe 内嵌网页在移动端无法滚动及多滚动条问题

blog.csdn.net/baidu_41828…

18、移动端页面弹窗滚动,页面也随之滚动解决方案

@touchmove="e => { e.preventDefault(); }"
复制代码

四、移动端踩坑日志(原理与源码)

1、1px 问题

表现

在移动端web开发中,UI设计稿中设置边框为1像素,前端在开发过程中如果出现border:1px,测试会发现在retina屏机型中,1px会比较粗,即是较经典的移动端1px像素问题。

问题原因

设备像素比:dpr=window.devicePixelRatio,也就是设备的物理像素与逻辑像素的比值。在retina屏的手机上, dpr为2或3,css里写的1px宽度映射到物理像素上就有2px或3px宽度。

解决方案

*1、0.5px 方案

IOS8+,苹果系列都已经支持0.5px了,可以借助媒体查询来处理。

/*这是css方式*/

.border { border: 1px solid #999 }
@media screen and (-webkit-min-device-pixel-ratio: 2) {
    .border { border: 0.5px solid #999 }
}
/*ios dpr=2和dpr=3情况下border相差无几,下面代码可以省略*/
@media screen and (-webkit-min-device-pixel-ratio: 3) {
    .border { border: 0.333333px solid #999 }
}
复制代码

IOS7及以下和Android等其他系统里,0.5px将会被显示为0px。那么我们就需要想出办法解决,说实在一点就是找到Hack。

解决方案是通过JavaScript检测浏览器能否处理0.5px的边框,如果可以,给html标签元素添加个class。

if (window.devicePixelRatio && devicePixelRatio >= 2) {
  var testElem = document.createElement('div');
  testElem.style.border = '.5px solid transparent';
  document.body.appendChild(testElem);
}
if (testElem.offsetHeight == 1) {
  document.querySelector('html').classList.add('hairlines');
}
  document.body.removeChild(testElem);
}
// 脚本应该放在body内,如果在里面运行,需要包装 $(document).ready(function() {})
复制代码

然后,极细的边框样式就容易了:

div {
  border: 1px solid #bbb;
}
.hairlines div {
  border-width: 0.5px;  
}
复制代码

**优点:**简单,不需要过多代码。

**缺点:**无法兼容安卓设备、 iOS 7及以下设备。

*2. 伪类+transform

原理:把原先元素的border去掉,然后利用:before或者:after重做border,并 transform的scale缩小一半,原先的元素相对定位,新做的border绝对定位。

/*设备像素比*/
/*显示屏最小dpr为2*/
@media (-webkit-min-device-pixel-ratio: 2) {
    .border-1px::after {
        width: 200%;
        height: 200%;
        transform: scale(0.5);
        transform-origin: 0 0;
    }
}
复制代码

**优点:**所有场景都能满足,支持圆角(伪类和本体类都需要加border-radius)。

**缺点:**代码量也很大,对于已经使用伪类的元素(例如clearfix),可能需要多层嵌套。

2、iOS 滑动不流畅

表现

上下滑动页面会产生卡顿,手指离开页面,页面立即停止运动。整体表现就是滑动不流畅,没有滑动惯性。

问题原因

原来在 iOS 5.0 以及之后的版本,滑动有定义有两个值 auto 和 touch,默认值为auto。

-webkit-overflow-scrolling: touch; /* 当手指从触摸屏上移开,会保持一段时间的滚动 */
-webkit-overflow-scrolling: auto; /* 当手指从触摸屏上移开,滚动会立即停止 */
复制代码

解决方案

全局滚动:滚动条在body节点或更顶层;

局部滚动:滚动条在body下的某一个dom节点上;

ios开发

全局滚动:默认支持

局部滚动:默认没有滚动条,且滑动起来干涩。

body{-webkit-overflow-scrolling:touch;} (快速滚动和回弹)
/*局部滚动的dom节点*/
.scroll-el{overflow:auto;}
复制代码

建议:将属性挂在body上,可以避免很多奇怪的bug。

3、iOS 上拉边界下拉出现白色空白

表现

手指按住屏幕下拉,屏幕顶部会多出一块白色区域。手指按住屏幕上拉,底部多出一块白色区域。

产生原因

在 iOS 中,手指按住屏幕上下拖动,会触发 touchmove 事件。这个事件触发的对象是整个 webview 容器,容器自然会被拖动,剩下的部分会成空白。

在 W3C 文档中说:

touchmove 事件的速度是可以实现定义的,取决于硬件性能和其他实现细节

preventDefault 方法,阻止同一触点上所有默认行为,比如滚动

解决方案

监听事件禁止滑动,通过监听 touchmove,让需要滑动的地方滑动,不需要滑动的地方禁止滑动。

//这个ios13以上没有效果
document.body.addEventListener('touchmove', function(evt) {
  if(!evt._isScroller) {
    evt.preventDefault();
  }
});
//这个会完全禁止touchmove  导致内部无法滚动。
document.body.addEventListener('touchmove', function (e) {
  if(e._isScroller) return; //过滤掉具有滚动容器的元素。
    e.preventDefault();
  }, {passive: false}
  ); //passive 参数不能省略
复制代码

4、页面放大或缩小不确定性行为

表现

双击或者双指张开手指页面元素,页面会放大或缩小。

产生原因

HTML 本身会产生放大或缩小的行为,比如在 PC 浏览器上,可以自由控制页面的放大缩小。但是在移动端,我们是不需要这个行为的。所以,我们需要禁止该不确定性行为,来提升用户体验。

原理与解决方案

HTML meta 元标签标准中有个 中 viewport 属性,用来控制页面的缩放,一般用于移动端。

移动端常规写法。

<meta name="viewport" content="width=device-width, initial-scale=1.0">
复制代码

因此我们可以设置 maximum-scale、minimum-scale 与 user-scalable=no 用来避免这个问题。

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

width=device-width :表示宽度是设备屏幕的宽度

initial-scale=1.0:表示初始的缩放比例

minimum-scale=0.5:表示最小的缩放比例

maximum-scale=2.0:表示最大的缩放比例

user-scalable=yes:表示用户是否可以调整缩放比例

5、click在 ios上有300ms延时与穿透

表现

1、延时:监听元素 click 事件,点击元素触发时间延迟约 300ms。

2、穿透:点击蒙层,蒙层消失后,下层元素点击触发。

产生原因

1、为什么会产生 click 延时?

iOS 中的 safari,为了实现双击缩放操作,在单击 300ms 之后,如果未进行第二次点击,则执行 click 单击操作。也就是说来判断用户行为是否为双击产生的。但是,在 App 中,无论是否需要双击缩放这种行为,click 单击都会产生 300ms 延迟。

2、为什么会产生 click 点击穿透?

双层元素叠加时,在上层元素上绑定 touch 事件,下层元素绑定 click 事件。由于 click 发生在 touch 之后,点击上层元素,元素消失,下层元素会触发 click 事件,由此产生了点击穿透的效果。

原理与解决方案

1、click 延时解决方案

  1. 禁止双击缩放

完全禁止缩放了,例如,想放大查看某张图片也是不被允许的

适用场景: 无需用户放大查看的元素页面、游戏页面等(注:ios10以前,上面是有效的)

  1. 指针事件 (Pointer Events)

    // touch-action 值为none时,禁用元素(及其不可滚动的后代)上的所有手势 html{touch-action: manipulation;}

触摸动作也经常用于完全解决由支持双击缩放手势引起的点击事件的延迟。

  1. 利用fastClick

其原理是:检测到touchend 事件后,会通过DOM自定义事件立刻出发模拟click事件,并且把浏览器300毫秒之后真正发的事件给阴断掉。

FastClick 使用方法: 在 window load 事件之后,在 上调用 FastClick.attach()

window.addEventListener( "load", function() {   
  	FastClick.attach( document.body ); 
}, false );
复制代码

2、click 点击穿透

使用 touchstart 替换 click 不仅解决了 click 事件都延时问题,还解决了穿透问题。因为穿透问题是在 touch 和 click 混用时产生。

在原生中使用

el.addEventListener("touchstart", () => {    
  console.log("ok"); }, false);
复制代码

6、软键盘将页面顶起来、收起未回落问题

表现

Android 手机中,点击 input 框时,键盘弹出,将页面顶起来,导致页面样式错乱。

移开焦点时,键盘收起,键盘区域空白,未回落。

产生原因

我们在app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 absolute 和 fixed 定位的元素。导致可视区域变小,布局错乱。

原理与解决方案

1、软键盘将页面顶起来的解决方案,主要是通过监听页面高度变化,强制恢复成弹出前的高度。

// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;
  window.onresize = function(){
    var resizeHeight = document.documentElement.clientHeight || document.body.clientHeight;
    if(resizeHeight < originalHeight ){
    // 恢复内容区域高度
}}

// 记录原有的视口高度
const originalHeight = document.body.clientHeight || document.documentElement.clientHeight;  
window.onresize = function(){    
    var resizeHeight = document.documentElement.clientHeight || 
    document.body.clientHeight;    
    if(resizeHeight < originalHeight ){    // 恢复内容区域高度}}
复制代码

2、h5动画效果(脱离文档流),输入框无法输入问题。

软键盘与输入框配合问题(注:软键盘弹出时,用户无法在输入框输入内容)(常用)

1)js:("body").height(("body").height(("body").height()); //设置页面动态高度

2)css:#wrap{width:100%;height:100%;position:relative;overflow:hidden;} 找到父元素

注:建议不要用fixed定位,用absolute定位。

键盘不能回落问题出现在 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));
}
复制代码

7、iPhone X系列安全区域适配问题

表现

头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。

产生原因

iPhone X 以及它以上的系列,都采用刘海屏设计和全面屏手势。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。

解决方案

设置安全区域,填充危险区域,危险区域不做操作和内容展示。

危险区域指头部不规则区域,底部横条区域,左右触发区域。

  1. 设置 viewport-fit 为 cover (需要适配 iPhoneX 必须设置 viewport-fit=cover,这是适配的关键步骤)

  2. 增加适配层 使用 safe area inset 变量

    /* 适配 iPhone X 顶部填充*/ @supports (top: env(safe-area-inset-top)){ body, .header{ padding-top: constant(safe-area-inset-top, 40px); padding-top: env(safe-area-inset-top, 40px); padding-top: var(safe-area-inset-top, 40px); } } /* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */ @supports (bottom: env(safe-area-inset-bottom)){ body, .footer{ padding-bottom: constant(safe-area-inset-bottom, 20px); padding-bottom: env(safe-area-inset-bottom, 20px); padding-top: var(safe-area-inset-bottom, 20px); }

8、移动开发之touch篇(重要)(实验操作:jquery 支持touch 事件)

touchstart 触摸开始(手指放在触摸屏上)

touchmove 拖动(手指在触摸屏上移动)

touchend 触摸结束(手指从触摸屏上移开)

当然还有一个touchcancel,是在拖动中断时候触发。(系统中断)

touchmove e.preventDefault() 方法可以取消与事件关联的默认动作

移动端WEB开发,click,touch,tap事件浅析

click 和 tap 比较

两者都会在点击时触发,但是在手机WEB端,click会有 200~300 ms,所以请用tap代替click作为点击事件。

关于tap的点透处理

在使用zepto框架的tap来移动设备浏览器内的点击事件,来规避click事件的延迟响应时,有可能出现点透的情况,即点击会触发非当前层的点击事件。

touch事件touch是针对触屏手机上的触摸事件。现今大多数触屏手机webkit内核提供了touch事件的监听,让开发者可以获取用户触摸屏幕时的一些信息。

触摸屏的相应顺序为 touchstart-->touchmove-->touchend-->click

分类:
前端
标签:
分类:
前端
标签: