引言

有一些 H5 开发者耳熟能详的问题。

比如,老板会问你:“你这个 H5 页面为什么这么卡?为啥 IOS 那么流畅?”,

再比如,业务方会问你:“为什么这个功能你做不了?人家 Native 可以做?”,

再再比如,交互甚至也会经常挑战你:“为什么安卓能做到这样的交互效果,你不可以?”。

我只想说,作为 H5 开发,我们是有苦衷的 =,=

心痛的简直无法呼吸。

这个问题确实困扰了挺久

H5 页面中,浏览器/安卓 的 back(返回) 键,默认会直接后退到上一个页面,这听起来似乎十分正常。

但是对于一个以 Web App 为导向的产品来讲,当前习惯 APP 交互操作的用户的第一反应应该会是:如果当前页面有浮层的话,先解散浮层(不管你承不承认,事实如此)。

话不多说直接上图:

点击浏览器回退直接。。。 体验不够好!!!

说实话,关于这个交互的优化,一开始我是拒绝的。

浏览器默认行为!你要我怎样?我即便是改了,有很多副作用你知道吗?history 你能随随便便玩得起?

直到某天灵(kan)机(dao)一(jing)动(pin),有(bei)了(da)头(lian)绪(le)。

我觉得不做不行了

一样的套路,要把大象装冰箱,总共分几步?

第 1 步:浮层被点击唤起时,为 URL Push 一个 Hash 值(要唯一);
第 2 步:浮层被用户通过自定义关闭按钮解散时,主动去掉对应 Hash;
第 3 步:监听hashchange事件,用户点击浏览器/安卓回退按钮时,解散对应浮层(通过唯一 Hash 值匹配),此时 Hash 值会被浏览器默认 pop 掉,这也是点击回退之后浏览器并不回到前一个页面的关键,因为正常的路由并没有变化!!!

Done~

现在看起来就像那么回事了:

当然,还有复杂一点的,嵌套浮层的 case 需要考虑。不过这时候我觉得已经触及我文字表达能力的盲区了 =,=

上代码:

这是我封装好的一个 React 组件 Enback 的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import React from 'react';
import PropTypes from 'prop-types';
class Enback extends React.Component {
static defaultProps = {
uniqueKey: 'newPop'
}
static propTypes = {
uniqueKey: PropTypes.string
}
constructor(props) {
super(props);
}
componentDidMount = () => {
const { uniqueKey, popStateCallback } = this.props;
const state = {
uniqueKey: uniqueKey
};
if (location.hash) {
history.pushState(state, null, `${location.hash}/${uniqueKey}`);
} else {
history.pushState(state, null, `#${uniqueKey}`);
}
window.addEventListener('hashchange', function(e) {
const popHash = e.oldURL.replace(e.newURL, '');
if (popHash === uniqueKey || popHash === `#${uniqueKey}` || popHash === `/${uniqueKey}`) {
popStateCallback(uniqueKey); // 回调函数中解散对应浮层
}
});
}
componentWillUnmount = () => {
const { uniqueKey } = this.props;
if (location.hash && location.hash.indexOf(uniqueKey) !== -1) {
history.go(-1);
}
}
render() {
return this.props.children;
}
}
export default Enback;

这是用法:

1
2
3
4
5
6
7
8
9
10
11
// Useage
import Enback from '../../enback';
export default () => (
<Enback
uniqueKey = "uniqueKey"
popStateCallback = { ()=> {/* here to hide your popup*/} }
>
<div> This is a popup </div>
</Enback>
);

不玩 React?没关系,这里有原生的做法:https://github.com/zhaoqize/blog/issues/20

BTW, 副作用其实还是有的。你们猜猜是啥?

At last

谢谢捧场,欢迎 issue 讨论,随手点个 Star 更好 →_→ GitRepo