移动端领域玄学集合

滚动不流畅

在滚动的容器中添加以下属性,在IOS中实现弹性滚动

1
-webkit-overflow-scrolling : touch;

如若在滚动事件上的绑定,可以在检测兼容性之后,使用passive事件绑定优化性能。
因为在移动端会默认先去执行listener,判断里面是否会阻止默认事件(e.preventDefaut())。如果没有,才会触发默认事件(如这里说的滚动),所以如果我们的事件绑定不想阻止默认事件的话,可以将passive = true,这样浏览器就会无阻塞的执行默认事件了。

1
2
3
4
5
XXX.addEventListener(type, listener, {
capture: false,
passive: true,
once: false
})

安卓设备,输入框弹出时,屏幕尺寸发生改变

这个神坑会带来几个常见的问题:

  • background-size: 100% 100%的全屏背景图变形
  • position: fixed的元素漂移,当键盘收起后不会恢复原位
  • position: absolute的根据bottom定位的元素位置不对
    解决办法:
  • 媒体查询一下或者JS监测一下,当页面高度低于多少时,设一个足够大或者写死的背景高度
  • 移动端尽量不用fixed
  • 想要尽量完美就耀用js或者媒体查询了,做一些特殊处理

某些版本的IOS设备,内容为纯数字的标签样式异常

在某些版本的IOS设备中,内容为纯数字的标签会会被浏览器解析成电话号码,表现类似于在原标签外包了一层标签。
这就有可能会对页面样式造成影响。

1
2
<span>12345678</span> <!-- you want it like this -->
<a><span>12345678</span></a> <!-- in fact -->

解决办法是头部加标签屏蔽该功能

1
<meta content="telephone=no" name="format-detection"/>

IOS9.3的iphone 5s下,微信内置浏览器屏幕宽度获取异常

在该版本系统下,DOMContentLoaded时,window.innerWidth获取到的屏幕宽度是980。
网上的方法是在meta里加上shrink-to-fit=no,然而似乎不起作用。

1
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1, shrink-to-fit=no">

目前还是保险起见的换了方法,用clientWitdh获取

1
var wid = document.body.clientWidth;

绝对定位叠加的元素错位或不显示

虽然元素排在后面,但依然会被前面的同班元素元素挡住,这时候加一个z-index明确层级。

1
2
3
.ab {
z-index: 1;
}

自定背景的input光标太长

需要加上appearance:none这个属性,它的作用是将input默认的属性样式去掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
.input-wrap input {
display: block;
width: 5.06rem;
height: .96rem;
margin: 0 auto;
border: none;
background: none;
color: #602f00;
vertical-align: middle;
font-size: .48rem;
-webkit-appearance:none; /* Safari 和 Chrome */
appearance:none;
}

Flex布局

要在微信端推广的web,现阶段尽量不要用flex布局,要不然800块的安卓及各种老机器会把你教育到怀疑人生。

iphone复制文字时内容错误

比如以下情况,12345前后的标签都设置了user-select:none,但是长按后调用系统复制,会发现复制到的内容是12345长按复制

1
2
3
4
5
<div>
<p style="user-select:none">你的抽奖号为:</p>
<p style="user-select:auto">12345</p>
<p style="user-select:none">长按复制</p>
</div>

最简单粗暴的解决办法就是在不影响布局的情况下调换一下标签顺序。。。

1
2
3
4
5
<div>
<p style="user-select:none">你的抽奖号为:</p>
<p style="user-select:none">长按复制</p>
<p style="user-select:auto">12345</p>
</div>

自动播放音频

监听页面上某张图片的加载事件

1
2
3
img.onload = function() {
audio.play();
}

判断是否是在移动端/微信中打开

1
2
3
if(/iphone|ios|android|mobile/i.test(navigator.userAgent.toLowerCase())) {
// 在移动端打开
}

同理,判断页面是否是在微信中打开

1
2
3
if(/micromessenger/i.test(navigator.userAgent.toLowerCase())) {
// 微信内置浏览器
}

判断横竖屏

监听onorientationchange/resize事件来判断屏幕方向发生了改变。
然后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", function(e){
if (window.orientation == 0 || window.orientation == 180) {
// 竖屏
} else {
// 横屏
}
// 或者根据屏幕宽度
if (document.body.clientWidth < document.body.clientHeight) {
// 竖屏
} else {
// 横屏
}
}, false);

websocket+cocos2d-js开发的游戏在微信中必须触摸屏幕才能接收到消息

讲真我还没找到这个玄学的原因,后来我改用EGRET引擎重写了客户端就没有这个现象了,服务端和通信模块一点没变……

video全屏播放

思路是用一个宽高均为100%的容器.video-wrap来包住video,再让video的高度等于容器的高度,进而实现全屏。

不过这里遇到了2个问题:

  • 在ios上,微信会默认调用原生的播放器来全屏播放视频,会出现白色的菜单和进度条,影响全屏的体验。
  • 在安卓上,微信会调用X5引擎底层播放器组件来播放视频,容器的z-index属性对其无效。此时也会出现菜单,而且最后还会无耻的出现“推荐视频”一栏…… 据说如果播放的是qq.com域名下的视频则不会碰到这个问题。

在ios中,我们用webkit-playsinline可以让webview使用H5的video直接播放,而不再出现菜单和进度条。

1
2
3
4
5
<div class="video-wrap">
<video id="video" height="100%" x-webkit-airplay="true" webkit-playsinline="true" preload="auto">
<source src="res/video.mp4">
</video>
</div>
1
2
3
4
5
6
7
8
9
10
.video-wrap {
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
background: url(../images/p2/bg.jpg);
background-size: cover;
/*display: none;*/
}
video { font-size: 100%; line-height: 0; vertical-align: baseline; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; outline: none; }

自动(定时)播放视频

在ios下,我们可以直接调用video的play方法实现视频的播放

1
2
3
4
5
6
setTimeout(function(){
// 原生
document.querySelector('#video').play();
// jQuery
$('video')[0].play();
}, 1000);

但在安卓下,由于X5内核绑架了video标签,而且要求视频首次播放时,必须是由用户亲自点击事件触发的才能播放,所以setTimeout不能调用play方法,并且也不能用js去触发click事件……X5内核视频播放官方问题集
解决的办法:
A.改成用户点击某个按钮后开始播放。
B.在游戏开始按钮时,先播放视频然后马上暂停,等到正式要播放视频时,就可以实现跟ios一样的调用方法了。

监听视频播放完毕

当视频播放完毕后我们希望它能自动隐藏掉并跳到其他界面。
video提供了一个视频播放完毕后的事件ended

1
2
3
document.querySelector('#video').addEventListener('ended', function(evt) {
document.querySelector('.video-wrap').innerHTML('');
});