跳到主要内容

移动端前端技巧指南

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. 唤醒原生应用

可以使用location.href来通过URL Scheme与原生应用建立通讯渠道. 基本格式为:

scheme://[path][?query]scheme://[path][?query]

其中:

  • scheme: 应用标识, 表示应用在系统里的唯一标识
  • path: 应用行为, 表示应用某个页面或者功能
  • query: 应用参数, 表示应用页面或应用功能所需要的条件参数

URL Scheme一般由前端与客户端共同协商. 有些环境下无法使用, Safari和微信浏览器会默认禁用该行为, 不过微信浏览器可以开启白名单让其生效

<!-- 打开微信 -->
<a href="weixin://">打开微信</a>

<!-- 打开支付宝 -->
<a href="alipays://">打开支付宝</a>

<!-- 打开支付宝的扫一扫 -->
<a href="alipays://platformapi/startapp?saId=10000007">打开支付宝的扫一扫</a>

<!-- 打开支付宝的蚂蚁森林 -->
<a href="alipays://platformapi/startapp?appId=60000002">打开支付宝的蚂蚁森林</a>

5. 禁止页面缩放

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

6. 禁止页面缓存

<meta http-equiv="Cache-Control" content="no-cache">

7. 禁止字母大写

有时候会在输入框中输入文本会默认开启首字母大写纠正, 下面的属性可以关闭该功能

<input autocapitalize="off" autocorrect="off">

8. 针对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">

9. 针对其他浏览器的配置

<!-- 强制QQ浏览器竖屏 -->
<meta name="x5-orientation" content="portrait">

<!-- 强制QQ浏览器全屏 -->
<meta name="x5-fullscreen" content="true">

<!-- 开启QQ浏览器应用模式 -->
<meta name="x5-page-mode" content="app">

<!-- 强制UC浏览器竖屏 -->
<meta name="screen-orientation" content="portrait">

<!-- 强制UC浏览器全屏 -->
<meta name="full-screen" content="yes">

<!-- 开启UC浏览器应用模式 -->
<meta name="browsermode" content="application">

<!-- 开启360浏览器极速模式 -->
<meta name="renderer" content="webkit">

10. 让:avtive有效, 让:hover失效

有些元素的:avtive可能会无效, 而元素的:hover在点击之后会一直处于点击状态, 需要点击其他位置才能解除点击状态, 给<body>注册一个空的touchestart事件可以将两种状态翻转

JavsScript

1. 禁止点击穿透

移动浏览器中的点击操作会存在300ms的延迟, 往往会造成点击延迟甚至点击无效

这是为了进行双击检测

改行为引发的点击延迟就被称为点击穿透

现在我们可以用fastclick解决该问题, 该解决方案监听用户是否做了双击操作, 可以正常的使用click事件

import Fastclick from "fastclick";

FastClick.attach(document.body);

其大致原理是在检测到toucheend事件的时候, 会通过DOM自定义事件立即发出, 模拟一个clik事件, 并把浏览器在300ms之后真正的click事件阻止掉.

2. 禁止滑动穿透

移动浏览器中在屏幕上的滑动会触发弹窗底下的内容跟着滚动.

目前很多解决方案都有其缺陷, 比如禁止body的滚动却引发了其他的问题:

  1. 弹窗打开后内部内容无法滚动
  2. 弹窗关闭后页面滚动丢失
  3. webview能上下滑动露出底色

当打开弹窗给body声明: position:fixed;left:0;width:100%并动态声明top. 声明position:fixed会导致滚动条消失.

另外的方案是scrollingElement获取scrollTop/ScrollHeight:

body.static {
position: fixed;
left: 0;
width: 100%;
}
const body = document.body;
const openBtn = document.getElementById("open-btn");
const closeBtn = document.getElementById("close-btn");
openBtn.addEventListener("click", e => {
e.stopPropagation();
const scrollTop = document.scrollingElement.scrollTop;
body.classList.add("static");
body.style.top = `-${scrollTop}px`;
});
closeBtn.addEventListener("click", e => {
e.stopPropagation();
body.classList.remove("static");
body.style.top = "";
});

3. 支持往返刷新

点击移动端浏览器的前进和后退按钮, 有时候不会自动执行旧页面的JS代码, 这与往返缓存有关, 简单的说就是往返页面无法刷新

往返缓存指浏览器为了在页面间执行前进后退操作的时候能拥有更流畅体验的一种策略. 简称BFCCache. 具体表现为: 当用户前往新页面的时候, 将旧页面的DOM状态保存在BFCCache中, 当用户返回旧页面, 将DOM状态从缓存中取出来.

// 在新页面监听页面销毁事件
window.addEventListener("onunload", () => {
// 执行旧页面代码
});

如果是在vue中, 可以将接口请求放到beforeRouteEnter中.

当然还有另外一种解决方案, 即在pageShow事件中去处理

window.addEventListener("pageshow", e => e.persisted && location.reload());

或者直接禁用缓存:

<meta http-equiv="Cache-Control" content="no-cache">

4. 解析有效日期

苹果系统上解析YYYY-MM-DD HH:mm:ss会报错, 但在安卓上就没有问题. 需要将-变为/:

const date = "2019-03-31 21:30:00";
new Date(date.replace(/\-/g, "/"));

5. 解决高度坍塌

在同时出现下面三个条件的时候, 键盘占位会把页面的高度压缩一部分. 当输入完成键盘消失后, 页面高度有可能回不到原来高度, 产生坍塌导致wevbview底色卢丽安. 简单概括就是输入框失焦后页面没有回弹.

  • 页面高度过小
  • 输入框在页面底部或者视窗中下部分
  • 输入框聚焦输入文本

只要保持前后滚动条偏移量一致就不会出现这个问题.

const input = document.getElementById("input");
let scrollTop = 0;
input.addEventListener("focus", () => {
scrollTop = document.scrollingElement.scrollTop;
});
input.addEventListener("blur", () => {
document.scrollingElement.scrollTo(0, this.scrollTop);
});

6. 修复输入监听问题

在苹果系统上的输入框输入文本, keyup/keydown/keypress事件可能会无效. 当输入框监听keyup时, 逐个输入英文和数字会有效, 单输入中文不会有效, 需要按回车才行. 此时可以用input事件代替keyup/keydown/keypress事件

7. 简化回到顶部

DOM对象中隐藏了一个很好用的函数可以完成上述功能.

就是scrollIntoView, 它会滚动目标元素的父元素使之对用户可见, 简单概括就是相对视窗让容器滚动到目标元素位置:

const gotopBtn = document.getElementById("gotop-btn");
openBtn.addEventListener("click", () => document.body.scrollIntoView({ behavior: "smooth" }));

其中有三个可选参数可以让其滚动更加优雅:

  • behavior: 动画过渡效果, 默认auto无, 可以改为smooth平滑
  • inline:水平方向对齐方式,默认nearest就近对齐,可选start顶部对齐、center中间对齐和end底部对齐
  • block:垂直方向对齐方式,默认start顶部对齐,可选center中间对齐、end底部对齐和nearest就近对齐

只需要将document.body改成目标元素的DOM对象, 也可以滚动到目标元素位置.

8. 简化惰性加载

以图片懒加载为例, 可以用IntersectionObserver简化图片懒加载.

<img data-src="pig.jpg">
const imgs = document.querySelectorAll("img.lazyload");
const observer = new IntersectionObserver(nodes => {
nodes.forEach(v => {
if (v.isIntersecting) { // 判断是否进入可视区域
v.target.src = v.target.dataset.src; // 赋值加载图片
observer.unobserve(v.target); // 停止监听已加载的图片
}
});
});
imgs.forEach(v => observer.observe(v));

另外一个场景, 下载加载:

<ul>
<li></li>
<!-- 很多<li> -->
</ul>
<!-- 也可将#bottom以<li>的形式插入到<ul>内部的最后位置 -->
<div id="bottom"></div>
const bottom = document.getElementById("bottom");
const observer = new IntersectionObserver(nodes => {
const tgt = nodes[0]; // 反正只有一个
if (tgt.isIntersecting) {
console.log("已到底部,请求接口");
// 执行接口请求代码
}
})
bottom.observe(bottom);

9. 优化扫码识别

通常移动端会配备长按二维码图片识别链接的功能. 但是二维码的实现可能会有img, svg或者canvas三种实现啊发那个是.

应该尽量使用img渲染二维码.

10. 自动播放媒体

大部分移动端浏览器明确规定不能自动播放媒体或者默认屏蔽了autoplay, 为了让媒体在页面加载后自动播放, 只能显示声明播放:

const audio = document.getElementById("audio");
const video = document.getElementById("video");
audio.play();
video.play();

对于微信浏览器这样的, 还需要监听应用的SDK加载完成才能出发上述代码, 保障webview的正常渲染:

document.addEventListener("WeixinJSBridgeReady", () => {
// 执行上述媒体自动播放代码
});

在苹果上明确规定用户交互操作开始后才能播放媒体, 未得到用户响应会被safari自动拦截, 所以需要监听用户首次触摸操作开始并出发媒体自动播放:

document.body.addEventListener("touchstart", () => {
// 执行上述媒体自动播放代码
}, { once: true });

参考链接