返回

页面离开通知:visibilitychange与beforeunload详解

vue.js

创建用户离开标签页或页面的通知

页面跳转行为检测很常用。检测用户是否要离开页面。应用场景多为提示用户进行内容保存或者做一些问卷调查。浏览器标签页的交互状态。有多种情况。了解如何监听页面状态变化,才能实现提示效果。

理解 visibilitychange 事件

visibilitychange 是一类用于通知文档的可见性状态发生变化的事件。这个事件让开发者可以知道网页的内容是否对用户可见。了解一下它的常见状态:

  • hidden: 表示文档至少部分被其他内容遮挡。通常来说,这意味着该文档是后台标签页、或者已经最小化。
  • visible: 表示文档至少在某个窗口的一部分可见。通常来说,这意味着文档作为某个非最小化窗口的前台标签页存在。
  • prerender: 表示文档正在屏幕外被加载和渲染。虽然可能用户看不见。文档可能会从此状态变为 visible(此时永不变为 hidden 状态)。但是反过来是不行的,visible状态是不会变成prerender状态的。

注意:在 prerender 状态,并非所有的功能都被浏览器支持。通常会有比较严格的功能约束条件。

通过侦听这个事件可以实现在用户离开当前页面或者切换标签页时弹出通知提醒的效果。

操作步骤:

  1. 在页面加载完成后添加 visibilitychange 事件监听器。
  2. 在事件处理函数中,检查 document.visibilityState 属性。
  3. 如果 visibilityStatehidden,则执行弹出通知的操作。

代码示例(JavaScript):

document.addEventListener('visibilitychange', function() {
  if (document.visibilityState === 'hidden') {
    // 使用浏览器通知 API 或自定义弹窗进行提示
    if (Notification.permission === "granted") {
      new Notification("请别离开我!", {
        body: "回来继续浏览吧。",
        icon: "/path/to/your/icon.png"
      });
    } else if (Notification.permission !== "denied") {
      Notification.requestPermission().then(function (permission) {
        if (permission === "granted") {
          new Notification("请别离开我!", {
            body: "回来继续浏览吧。",
            icon: "/path/to/your/icon.png"
          });
        }
      });
    }
  }
});

使用 beforeunload 事件

beforeunload 事件。用于捕获用户尝试关闭或刷新页面时的动作。这个事件能让我们阻止默认操作,在离开页面时给出用户提示框,比如确认他们是否真要离开或者保存一下信息等。

虽然beforeunload 事件能让用户在离开页面前收到提醒。但是和题主的需求“标签页切换时提示”有一些差别。beforeunload主要关注页面是否被关闭。只有页面刷新和关闭才能捕获到。标签页切换是不会触发这个事件的。

操作步骤:

  1. 在页面加载完成后添加 beforeunload 事件监听器。
  2. 在事件处理函数中,设置 event.returnValue 或返回一个字符串以触发确认对话框。

代码示例(JavaScript):

window.addEventListener('beforeunload', function (event) {
  // 取消事件(标准做法)
  event.preventDefault();
  // 为了兼容,可以设置一个 returnValue 属性
  event.returnValue = '你确定要离开页面吗?未保存的数据可能会丢失!';
  return '你确定要离开页面吗?未保存的数据可能会丢失!'; 
});

注意: 部分浏览器的较新版本不再支持 beforeunload 事件弹出的自定义消息。但是浏览器会显示一个默认提示,询问用户是否要离开页面。这是出于安全性和用户体验的考虑,避免滥用弹窗打扰用户。

安全建议

  • 不要过度使用通知。过多弹出可能会影响用户体验。
  • 应该清晰告知用户通知的目的。提供退出选项或链接。让用户能轻松理解为什么会被通知打扰,可以按需操作或者快速关掉提醒。
  • 在使用 Notification API 时,需注意兼容性以及请求用户授权通知权限。

结合使用两种方法增强用户体验

综合两种方式进行提示,以保证功能能达到一个最好的提示效果:

  • 使用 visibilitychange 事件在用户切换到其它标签页或者最小化浏览器窗口时,给出提示。这个主要应对标签页之间切换的时候弹出通知的情况。
  • 使用 beforeunload 事件在用户尝试关闭标签页、浏览器窗口或刷新页面时给出二次确认提示。这种操作能最大程度减少误操作,以及一些信息的错误丢失。
// 标签页切换事件检测
document.addEventListener('visibilitychange', function() {
  if (document.visibilityState === 'hidden') {
    if (Notification.permission === "granted") {
      new Notification("您切换了标签页!", {
        body: "回来看看有什么新内容吧!",
        icon: "/path/to/your/icon.png"
      });
    } else if (Notification.permission !== "denied") {
      Notification.requestPermission().then(function (permission) {
        if (permission === "granted") {
          new Notification("您切换了标签页!", {
            body: "回来看看有什么新内容吧!",
            icon: "/path/to/your/icon.png"
          });
        }
      });
    }
  }
});

// 关闭和刷新检测,提示数据可能丢失,防止误操作
window.addEventListener('beforeunload', function (event) {
  event.preventDefault();
  event.returnValue = '确认离开?'; 
});

与前端框架结合 (Vue.js)

当和Vue一起用时。把这些逻辑写进组件的生命周期函数就行。比如说,你想在一个组件里控制离开提示的话。可以直接写mountedbeforeDestroy 这些生命周期钩子函数中。
以下给一个简单的实例。

操作步骤:

  1. 在 Vue 组件的 mounted 生命周期钩子中添加事件监听器。
  2. 在 Vue 组件的 beforeDestroy 生命周期钩子中移除事件监听器,避免内存泄漏。

代码示例:

<template>
  <div>
    </div>
</template>

<script>
export default {
  mounted() {
    // 添加事件监听器
    document.addEventListener('visibilitychange', this.handleVisibilityChange);
    window.addEventListener('beforeunload', this.handleBeforeUnload);
  },
  beforeDestroy() {
    // 移除事件监听器
    document.removeEventListener('visibilitychange', this.handleVisibilityChange);
    window.removeEventListener('beforeunload', this.handleBeforeUnload);
  },
  methods: {
    handleVisibilityChange() {
      if (document.visibilityState === 'hidden') {
                if (Notification.permission === "granted") {
          new Notification("您切换了标签页", {
            body: "回来看看吧",
            icon: "/path/to/your/icon.png"
          });
        } else if (Notification.permission !== "denied") {
          Notification.requestPermission().then(function (permission) {
            if (permission === "granted") {
              new Notification("您切换了标签页", {
                body: "回来看看吧",
                icon: "/path/to/your/icon.png"
              });
            }
          });
        }
      }
    },
    handleBeforeUnload(event) {
      event.preventDefault();
      event.returnValue = '确认离开?';
    }
  }
};
</script>

按照上边的步骤一步一步走下来。把检测状态的方法封装进一个vue组件中。能通过Notification的API在用户要离开标签页时候,发个通知去挽留。或者利用beforeunload事件提示未保存的信息。就能保证最大程度地减少因为误操作带来的风险和数据的损失了。

总结一下,做提示检测。关键要知道用什么办法最灵光,最管用。这样既实用也照顾到用户的感觉。visibilitychangebeforeunload 都是检测用户状态变化的好方法,通过他们的合理结合,就可以满足用户提示这一功能的需求。