浏览器“后退”、“前进”或可以这么去监听

本文介绍了一种利用hashchange事件而非onbeforeunload事件来拦截用户离开页面的方法,通过监听hash变化并结合history.pushState来实现在用户点击浏览器后退按钮时弹出确认框,以收集用户离开原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们知道,浏览器实现了onbeforeunloadonunload事件,onbeforeonload事件是在浏览器即将请求下一个页面(请求还未发出)的时候触发,它可以实现阻止onunload的触发。onunload事件则是浏览器已经将下一个页面请求回来,页面即将跳转的时候触发,该事件无法中断。看起来onbeforeunload事件似乎能满足我们的需求,但是,这只是一个假象。

onbeforeunload事件虽然能阻止onunload事件的触发,但是由于它是浏览器内置的事件,其出现的交互方式和UI界面,均由浏览器厂商控制,并未提供给开发者定义浮层内部内容更多交互的接口,甚至文本性质的提示内容也无法设置样式。所以,想要通过onbeforeunload事件提供的浮层实现收集用户离开的原因或让用户给应用打分的功能并不现实。

下面我就详细描述下我做的思路,不过我要先声明以下几点:

  • 该方案只能部分解决需求,并不能完美解决问题
  • 这只是一种尝试,并未正式应用于业务
  • 该方案涉及history.pushState方法、popstate事件以及功臣hashchange事件

在进入主题之前,我们先来罗列几个小知识点:

  • 浏览器离开一个页面,意味着链接地址(不含hashchange、pushState方式)发生变化
  • history.pushState可以改变地址栏链接地址,但不触发页面刷新(不离开)
  • hash变化会触发popstate事件和hashchange事件
  • popstate事件对象可以获得pushState传递进去的state属性,从而得到变化后的链接地址等
  • hashchange事件对象中包含变化前后的链接地址(oldURL和newURL)
  • 浏览器的“前进”、“后退”可以触发hashchange事件

 我首先想到的是,当页面加载完成时,通过status变量标记页面状态为0。利用代码push一个链接到history中,status状态改为1,标记此时链接变化了,但页面并未刷新。当用户点击浏览器“后退”按键的时候,浏览器地址首先返回页面的原始链接地址,页面并不会刷新,此时触发popstate事件,只需在事件函数中判断status === 1时出现弹层即可:

 1 var status = 0,
 2     // 存储浮层节点
 3     pop = document.getElementById('J_PageWrap');
 4 window.addEventListener('load', function() {
 5     var tit = document.title,
 6         path = location.href.replace(/#.*$/, '') + '#!hash';
 7     // 将追加了hash的链接推入history中
 8     history.pushState({title: tit, path: path}, tit, path);
 9     status = 1;
10 });
11 window.addEventListener('popstate', function(ev){
12     if (status == 1) {
13         status = 0;
14         pop.className += ' show'; // show为显示浮层样式
15     }
16 });

到这里,我们的基本功能实现了:用户进入页面后,第一次点击“回退”并不会离开页面,而是触发弹层,再次点击“回退”离开当前页面。

但是,新的问题出现了。如果页面中有其他hash锚点被点击的时候,页面不会跳转,但会触发popstate事件,此时浮层便会显示,但此时用户并没有离开页面,并且如果没有在浮层中添加隐藏浮层和重置status变量的逻辑,浮层将一直显示。

于是,我开始寻找如何判断popstate触发是从初次添加的hash链接跳回页面原始链接的方法。因为,如果不是页面onload的时候,用脚本pushState添加加了hash的链接,此时页面已经回退跳出了。所以,我开始尝试从popstate事件的事件对象中寻找链接的变化线路:

 

但是,很遗憾!我只从对象中发现了进入页面是通过pushState传入的state属性,并没有其他任何特征属性可以帮助到我。而单看这个属性,想要判断页面链接的变化情况,实在是太难了。至少要知道现在是什么,将要变成什么,才能有判断的可能,所以,我还需要找到另一个辅助数据。

我们知道,当页面hash变化的时候,还会触发hashchange事件。那么,在hashchange的时候,有没有什么可用的数据呢?

于是,我又给页面绑定了hashchange事件,来观察hashchange带来的变化:

window.addEventListener('hashchange', function(ev){
    console.log(ev);
});

本来只是想在popstate的基础之上,通过hashchange挖掘到另一个可用的数据,却没想到有了意外的发现:

hashchange的时间对象中,竟然内置了变化前(oldURL)后(newURL)的两个链接地址。这样一来,popstate的那段逻辑,在这里似乎就没那么必要了。于是,我将代码改造成了这样:

var pop = document.getElementById('J_PageWrap');
window.addEventListener('load', function() {
    var tit = document.title,
        path = location.href.replace(/#.*$/, '') + '#!hash';
    history.pushState({title: tit, path: path}, tit, path);
});
window.addEventListener('hashchange', function(ev){
    var oAddr = ev.oldURL.replace(/^.+(?=\/\/)/, ''), // 为避免http(s)的影响,去除协议进行判断
        nAddr = ev.newURL.replace(/^.+(?=\/\/)/, '');
    if (oAddr === '//10.14.132.43:808/tests/hash/index.html#!hash'
        && nAddr === '//10.14.132.43:808/tests/hash/index.html') {
        pop.className += ' show';
    } else {
        pop.className = 'page-wrap';
    }
});

当且仅当链接从带有#!hash返回页面原始链接的时候,设置浮层显示,否则浮层隐藏,这样就有比前面popstate的实现又进了一步。

至此,我们不仅保证了页面的正常操作,也实现了当用户点击浏览器“后退”按钮至即将离开页面的时候出现浮层,收集信息的需求。但是,还有很多问题仍然存在:

  • 如果用户进入过其他页面,再返回当前页面点击“前进”按钮的时候,并不能触发浮层
  • 在带有#!hash的时候,强制刷新页面也有可能导致“后退”路径异常
  • 直接关闭浏览器也是没办法咯

示例DEMO:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <meta name="viewport" content="width=device-width,initial-scale=1">
 6     <title>HASHCHANGE</title>
 7 <style>
 8     html, body {
 9         margin: 0;
10         padding: 0;
11         height: 100%;
12         overflow: hidden;
13     }
14     .page-wrap {
15         position: absolute;
16         top: 100%;
17         height: 30%;
18         width: 100%;
19         font-size: 250px;
20         line-height: 30vh;
21         text-align: center;
22         background-color: #f00;
23         color: #fff;
24         -webkit-transition: top .3s ease-out;
25         -o-transition: top .3s ease-out;
26         transition: top .3s ease-out;
27     }
28     .page-wrap.show {
29         top: 70%;
30     }
31     .page-main {
32         text-align: center;
33         line-height: 100vh;
34         font-size: 10vw;
35         font-weight: 600;
36     }
37 </style>
38 </head>
39 <body>
40     <div class="page-main">
41         <a href="#changeHash" target="_self">SecondPage</a>
42     </div>
43     <div id="J_PageWrap" class="page-wrap">0</div>
44 <script>
45 (function(){
46     var status = 0,
47         pop = document.getElementById('J_PageWrap');
48     window.addEventListener('load', function() {
49         var tit = document.title,
50             path = location.href.replace(/#.*$/, '') + '#!hash';
51         history.pushState({title: tit, path: path}, tit, path);
52         status = 1;
53     });
54     // window.addEventListener('popstate', function(ev){
55     //     console.log(ev);
56     //     if (status == 1) {
57     //         status = 0;
58     //         pop.className = 'page-wrap show';
59     //     }
60     // });
61     window.addEventListener('hashchange', function(ev){
62         // console.log(ev);
63         var oAddr = ev.oldURL.replace(/^.+(?=\/\/)/, ''),
64             nAddr = ev.newURL.replace(/^.+(?=\/\/)/, '');
65         if (oAddr === '//seejs.com/demos/examples/goback/index.html#!hash'
66             && nAddr === '//seejs.com/demos/examples/goback/index.html') {
67             pop.className += ' show';
68         } else {
69             pop.className = 'page-wrap';
70         }
71     });
72 })();
73 </script>
74 </body>
75 </html>

 转载至原文:http://web.jobbole.com/89526/

转载于:https://www.cnblogs.com/myclovers/p/6229687.html

<think>我们正在处理一个关于Vue中监听浏览器前进后退事件的问题。根据用户的需求,我们需要提供解决方案示例代码。同时,系统指令要求我们使用正确的LaTeX格式、中文回答,并生成相关问题。根据提供的引用内容,我们可以总结出:1.使用`popstate`事件监听浏览器前进后退操作。2.在Vue组件的生命周期钩子(如`created``mounted`)中添加事件监听。3.在组件销毁时(`destroyed``beforeDestroy`)移除事件监听,避免内存泄漏和重复监听。因此,我们可以给出以下解决方案:###解决方案在Vue中,可以通过监听`popstate`事件来响应浏览器前进后退操作。具体步骤如下:1.**在组件创建时添加事件监听**:在`created``mounted`生命周期钩子中,使用`window.addEventListener`监听`popstate`事件。2.**定义事件处理函数**:在方法中定义处理函数,当事件触发时执行相应的操作(例如路由跳转、状态更新等)。3.**在组件销毁时移除事件监听**:在`destroyed``beforeDestroy`生命周期钩子中,使用`window.removeEventListener`移除之前添加的事件监听。###示例代码以下是一个简单的示例代码,展示如何在Vue组件中实现监听浏览器前进后退事件:```vue<template><div><!--组件内容--></div></template><script>exportdefault{name:'MyComponent',created(){//添加popstate事件监听window.addEventListener('popstate',this.handlePopstate);},destroyed(){//移除事件监听window.removeEventListener('popstate',this.handlePopstate);},methods:{handlePopstate(event){//在这里处理浏览器前进后退事件console.log('浏览器前进后退操作被触发',event);//可以根据需要执行操作,例如://this.$router.push('/some-path');}}};</script>```###注意事项-**事件触发时机**:`popstate`事件会在浏览器前进后退操作时触发,但需要注意的是,当使用VueRouter进行路由跳转时,VueRouter已经内部处理了`popstate`事件。因此,如果你需要监听浏览器前进后退操作并执行一些额外的逻辑,请确保不会与VueRouter的默认行为冲突。-**移除监听**:务必在组件销毁时移除事件监听,否则可能会导致内存泄漏以及在其他组件中重复触发的问题。-**兼容性**:`popstate`事件在现代浏览器中支持良好,但如果你需要支持老版本浏览器,请考虑兼容性问题。###引用说明根据提供的引用内容:-引用[1]提到在`destroyed`生命周期中移除事件监听,以避免其他页面也被监听[^1]。-引用[2]提供了在`created`中添加监听和`destroyed`中移除监听的示例,并指出`popstate`事件在路由变化时触发[^2]。因此,我们的解决方案综合了这两点,确保代码的健壮性。§§相关问题§§1.VueRouter中如何监听路由变化?2.除了`popstate`事件,还有哪些方式可以监听浏览器历史记录的变化?3.在Vue中如何处理浏览器的刷新事件?</think>### Vue监听浏览器前进后退事件解决方案 在Vue中监听浏览器前进后退事件主要通过`popstate`事件实现,该事件会在用户点击浏览器前进/后退按钮调用`history.back()`/`history.forward()`时触发。以下是完整实现方案: #### 核心实现代码 ```vue <script> export default { created() { // 添加浏览器前进后退监听 window.addEventListener('popstate', this.handleBrowserNavigation); console.log("监听已启用"); }, beforeDestroy() { // 组件销毁前移除监听(避免内存泄漏) window.removeEventListener('popstate', this.handleBrowserNavigation); console.log("监听已移除"); }, methods: { handleBrowserNavigation(event) { // 获取当前路由路径 const currentPath = this.$route.path; // 处理前进后退逻辑 console.log('浏览器导航事件触发', event); console.log('当前路由:', currentPath); // 实际业务处理示例: // 1. 显示确认对话框 // 2. 保存表单数据 // 3. 执行特定路由逻辑 } } } </script> ``` #### 关键说明 1. **事件绑定时机** 在`created`生命周期钩子中添加事件监听,确保组件初始化后立即生效[^1] 2. **内存管理** 必须在`beforeDestroy``destroyed`中移除监听,防止组件销毁后事件仍在触发[^1][^2] 3. **路由信息获取** 通过`this.$route`可获取Vue Router的当前路由状态,结合导航动作实现业务逻辑 4. **事件对象** `popstate`事件的`event.state`包含历史记录的状态对象,可用于跟踪导航历史 #### 增强方案(路由拦截) 结合Vue Router的路由守卫实现更精细控制: ```javascript // router/index.js const router = new VueRouter({ ... }); router.beforeEach((to, from, next) => { if (window.history.state?.triggeredByPopstate) { console.log('通过浏览器按钮触发的导航'); // 执行特殊处理逻辑 } next(); }); ``` #### 注意事项 1. **SPA应用限制** `popstate`仅在单页面应用(SPA)内部路由变化时触发,完整页面跳转不会触发[^2] 2. **移动端兼容** 在移动设备上同样适用,可监听安卓/iOS设备的物理返回键 3. **与Vue Router协作** 当同时使用Vue Router时,建议在路由守卫中处理主要逻辑,`popstate`作为补充 4. **调试技巧** 在Chrome开发者工具的`Application > History`查看历史记录状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值