手机浏览器物理返回键
1. 物理返回键
1.1 需求
一个移动端的项目,产品希望页面上的返回按钮,和手机的物理返回键逻辑保持一致。需要满足下面几个要求
- 页面上的返回按钮,与物理返回键效果保持一致
- 返回后,点击物理前进键能正常前进
- 当前页面打开了一个组件,刷新页面,组件要正常显示
- 当用户打开一个新的tab,地址是/#/A?model=B,需要正常显示组件B
1.2 用例
- 页面A -> 组件B
- 页面A -> 组件B -> 页面A
- 页面A -> 组件B -> 组件C
- 页面A -> 组件B -> 刷新(组件B不会消失)
- 打开一个新页面(/#/A?modal=B) -> 组件B -> 点击返回 -> 页面A
1.3 解决方法
- 页面的返回按钮统一用
this.$router.go(-1)
- 显示弹框(组件)统一用
pushState
更改hash,向路由历史推入一个记录,使路由变成 /#/A?model=B。这里的页面A始终不会被刷新 - 组件内监听路由变化,监听到上面两个动作,执行显示和隐藏组件动作
- 访问地址/#/A?model=B,正常显示B。在组件的mounted方法,检查路由是否带modal, 如果是需要按需推进多个路由路径(保证后退正常)
1 | new Vue({ |
页面A -> 组件B -> 页面C,为了兼容页面C点击返回时,能显示组件B
页面A -> 组件B -> 组件C,同理在组件C推进路由1
2
3
4
5
6
7
8
9
10
11// 组件B
mounted () {
if (this.$route.query.modal && this.$route.query.modal == this.$options.name) {
// 从另一个路由返回,路由带modal参数
this.$router.replace({ path: `${this.$route.path}` })
this.$router.push({
path: `${this.$route.path}`,
query: { modal: this.$options.name }
})
}
},
这里存在两个问题
页面A -> 组件B -> 组件C -> 页面D
在页面D返回时候。 /#/A?model=C, 由于组件B 使用v-if来显示隐藏,此时组件B v-if=false,导致组件C没有挂载,C中的mounted方法无法执行改成v-show? 用v-if可以减少很多空值的兼容
页面A -> 组件B -> 页面D
页面A -> 组件C -> 组件B -> 页面D
上面的mounted方法里,定义了组件B在第二层。当其他地方调用的组件B在第三层,页面D返回时,显示组件B,再点击返回,就直接回到了页面A,组件C被跳过。这里限定了组件B只能在第二层。
2. 刷新当前路由
路由刷新的中转文件,注册一个路由 /refresh -> refresh.vue。调用 this.$router.replace({ path: '/refresh' })
来刷新当前路由。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<!-- refresh.vue -->
<template>
<div></div>
</template>
<script>
export default {
beforeRouteEnter (to, from, next) {
next(vm => {
const query = vm.$route.query || {}
const params = vm.$route.params || {}
const {
newRoute
} = params
// 1. newRoute 使用新的路由对象刷新界面
// 2. 使用原来的路径和新的参数刷新界面
vm.$router.replace(newRoute || {
path: from.path,
query,
params
})
})
}
}
</script>