如何在 JavaScript 事件中区分页面关闭和页面刷新?

往期文章:

在开发 Web 应用时,有时你可能需要监听用户关闭页面刷新页面的行为

例如,用户关闭当前页面清空token,而刷新时候不做处理。

例如,你可能想在用户离开页面时保存未保存的数据,或者在页面刷新时执行一些特定的操作。

如何区分这两种行为(关闭页面和刷新页面)却不是那么直观。

我们需要使用一些特定的 API,巧妙地实现这一功能。

在本文中,我们将使用 beforeunload 事件来监听浏览器页面的关闭与刷新行为,并通过几种不同的方法来区分它们。

使用 beforeunload 事件监听页面关闭和刷新

beforeunload 事件是浏览器在用户关闭页面刷新页面跳转到另一个页面时触发的事件。你可以通过这个事件来做一些清理工作,或者提示用户保存未保存的内容。最常见的应用场景是在页面关闭或刷新时弹出确认框。

监听 beforeunload 事件
window.addEventListener('beforeunload', function (event) {
  // 自定义提示消息
  const message = 'Are you sure you want to leave?';
  event.returnValue = message;  // 对老版本浏览器的支持
  return message;  // 对现代浏览器的支持
});

说明:

  • 当用户试图离开当前页面时(包括刷新或关闭页面),浏览器会显示一个确认框,询问用户是否确定离开。
  • event.returnValue 或者直接 return 提示消息都会触发浏览器的默认行为,弹出提示框。

注意:

  • 现代浏览器对这个事件的支持有所限制,特别是在弹出框的内容上。为了防止恶意行为,浏览器可能只显示默认的提示文本。
  • beforeunload 事件会在页面刷新和关闭时都被触发,因此无法直接区分这两者。

如何区分页面刷新与页面关闭

虽然 beforeunload 事件能够监听页面的关闭与刷新,但它不能直接告诉你是页面被刷新还是被关闭。为了实现这一点,我们需要使用一些额外的技巧。以下是几种方法:

方法 1:使用 sessionStorage 来区分刷新和关闭

如何利用 sessionStorage 判断页面是否是刷新?

  1. 初次加载:当页面第一次加载时,sessionStorage 是空的。
  2. 刷新页面:当页面被刷新时,sessionStorage 会保留在当前会话中,但它的内容不会被清空,直到页面被关闭。
  3. 关闭页面:当页面关闭时,sessionStorage 会被清空。

因此,我们可以通过在页面加载时设置一个标识符来检测是否是页面刷新。

实现代码:
// 页面加载时执行
window.onload = function() {
    // 检查 sessionStorage 中是否有标记
    if (sessionStorage.getItem('refreshed') === 'true') {
        console.log('页面被刷新');
        sessionStorage.removeItem('refreshed'); // 清除标记
    } else {
        console.log('页面被加载');
    }
};

// 监听 beforeunload 事件
window.addEventListener('beforeunload', function(event) {
    // 设置 sessionStorage 标记
    sessionStorage.setItem('refreshed', 'true');
});

// 监听 unload 事件
window.addEventListener('unload', function(event) {
    // 页面关闭时执行的操作
    console.log('页面被关闭');
});

解释:

  • 当页面加载时onload,我们判断 sessionStorage 中的 refreshed 标记设置为 true,表示页面已经刷新过。
  • beforeunload 事件触发时,我们设置 sessionStorage 中的标记为true
  • 刷新时候,sessionStorage中的值一直存在,关闭后sessionStorage值被清除。
方法 2:使用 localStorage 来区分刷新和关闭
https://segmentfault.com/a/1190000019305127)

在浏览器关闭前是无法判断用户是刷新还是退出,所以我们在用户再次打开的时候来判断用户是否刷新

解决思路:

  1. 用户关闭浏览器时,记录当前时间,并存于浏览器缓存中
  2. 用户再次打开页面时,获取上次退出的时间,并于当前时间进行比较,若小于5s则表示用户执行的是刷新操作,若大于5s则判定为退出

注意: 5s并非固定,要根据实际情况调整,(根据网速,一般刷新页面时间在五秒内,用户关闭再打开页面时间大于5s)

实现代码:
// 记录当前时间并转成时间戳
const currentTime = new Date().getTime();
// 从缓存中获取用户上次退出的时间戳
const lastTime = parseInt(localStorage.getItem('leaveTime'));
console.log(currentTime, lastTime, currentTime - lastTime, 'leaveTime');
// 判断是否为刷新,两次间隔在5s内判定为刷新操作
const isFreshed = currentTime - lastTime <= 5000;
// 测试alert
console.log(isFreshed ? '刷新' : '重新登陆');
window.addEventListener('beforeunload', (e)=>{
    let currentTime = new Date().getTime();
    localStorage.setItem('leaveTime', currentTime);
});
方法 3:使用 performance.navigation 判断页面刷新

浏览器的 performance.navigation 接口可以帮助我们判断页面是通过刷新加载的,还是通过点击链接或其他方式加载的。

实现代码:
window.addEventListener('beforeunload', function (event) {
  if (window.performance && window.performance.navigation.type === window.performance.navigation.TYPE_RELOAD) {
    // 页面被刷新
    console.log('The page is being refreshed.');
  } else {
    // 页面正在关闭
    console.log('The page is being closed.');
  }
});

解释:

  • performance.navigation.type
    

    返回一个数字,表示页面的加载类型:

    • 0TYPE_NAVIGATE):正常的页面加载(例如通过链接跳转)。
    • 1TYPE_RELOAD):页面刷新。
    • 2TYPE_BACK_FORWARD):通过浏览器的前进或后退按钮加载页面。
  • 通过检查这个值,我们可以判断当前页面是刷新还是关闭。

注意:

  • performance.navigation 在某些浏览器中可能不被完全支持,特别是在移动端设备上,建议在使用前进行兼容性测试。
方法4:使用 window.event.screenY 判断页面刷新(IE支持)
window.onbeforeunload = (e) => {
       if ((event.clientX > document.body.clientWidth && event.clientY < 0) || event.altKey) {
         alert('你关闭了浏览器')
      } else {
         alert('你正在刷新页面')
       }
       // e.returnValue = '确认关闭'
       return '确认关闭'
     }

总结

在 Web 开发中,有时你需要监听页面关闭或刷新事件,并根据情况执行不同的操作。通过以下几种方法,你可以实现对页面关闭和页面刷新的区分:

  1. beforeunload 事件: 可以监听页面关闭或刷新事件,但无法区分这两者。
  2. localStorage 通过设置时间戳标记,可以判断页面是否刷新。
  3. sessionStorage 通过sessionStorage特有特性实现效果
  4. performance.navigation 通过检查 performance.navigation.type,可以确定页面是否被刷新。

虽然 beforeunload 事件能处理很多场景,但如果你需要更精确的控制,可以结合 sessionStorageperformance.navigation 来判断页面是否刷新。

记住performance.navigation需要进行适当的兼容性测试。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐