一种方法可以阻止用户过度刷新

Avatar of Mateusz Rybczonek
Mateusz Rybczonek

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费信用额度!

页面重新加载是一个普遍现象。 有时,当我们认为页面没有响应或认为有新内容可用时,我们会刷新页面。 有时我们只是对该站点感到愤怒,并愤怒地刷新以让它知道我们不满意。

了解用户何时刷新页面不是很好吗? 不仅如此,还有多少次? 这些数据可以帮助我们在特定次数的重新加载后触发某种行为。

体育网站就是一个很好的例子。 如果我想查看正在进行的比赛的比分,但比分没有实时更新,那么我可能会发现自己刷新了很多次。

我们的目标是让用户改掉这种习惯。 我们将利用我们的页面刷新计数功能,让用户知道由于实时比分更新,刷新是不必要的。 而且,如果他们刷新超过三次? 我们将把他们踢出他们的会话。 这会告诉他们。

这是一个简单演示该概念的演示。

让我们一起重新创建它。 但是,在我们开始之前,我们需要在开始编码之前回答几个问题

  • 我们如何持久保存用户重新加载站点的次数? 我们需要一个地方来保存用户重新加载站点的次数(reloadCount),这个地方需要在重新加载之间持久保存该值——localStorage 听起来像是一个不错的解决方案。
  • 我们如何检测用户是重新加载了站点还是在几个小时后才回来? 如果我们将reloadCount存储在localStorage中,它将在重新加载之间持久保存该值,但它将保留该值,直到我们以编程方式删除或清除浏览器存储。 这意味着,如果我们几个小时后回来,该站点仍将记住上一次的reloadCount,并且可能会在没有警告的情况下在第一次刷新后执行注销。 我们想避免这种情况,并允许用户在每次用户在一段时间后回来时重新加载站点两次。 最后一句话包含了这个问题的答案。 我们需要存储用户离开站点的時間,然后在站点再次加载时检查发生的时间。 如果这段时间不够长,我们就激活重新加载计数逻辑。
  • 我们如何知道用户何时离开站点? 为了存储那个时间,我们使用beforeunload 窗口事件并将该值存储在localStorage中。

好的,现在我们有了答案,让我们深入代码。

步骤 1:我们必须存储上次重新加载的时间

我们将使用beforeunload 窗口事件存储上次重新加载的时间。 我们需要两件事:(1)一个事件侦听器,它将侦听事件并触发相应的 method,以及(2)我们的beforeUnloadHandler method。

首先,让我们创建一个名为initializeReloadCount 的函数,该函数将使用窗口对象上的addEventListener method 设置我们的事件侦听器。

function initializeReloadCount() {
  window.addEventListener("beforeunload", beforeUnloadHandler)
}

然后,我们创建一个将在我们离开站点之前触发的第二个 method。 该 method 将保存刷新发生的时间在localStorage中。

function beforeUnloadHandler() {
  localStorage.setItem("lastUnloadAt", Math.floor(Date.now() / 1000))
  window.removeEventListener("beforeunload", beforeUnloadHandler);
}

步骤 2:我们需要一种方法来处理和存储重新加载计数

现在我们有了上次站点关闭的时间,我们可以继续并实现负责检测和计数站点重新加载次数的逻辑。 我们需要一个变量来保存我们的reloadCount,并告诉我们用户重新加载站点的次数。

let reloadCount = null

然后,在我们的initializeReloadCount 函数中,我们需要做两件事

  1. 检查我们是否已经在我们的localStorage中存储了reloadCount值,如果有,获取该值并将其保存在我们的reloadCount中。 如果该值不存在,则意味着用户是第一次加载站点(或至少没有重新加载它)。 在这种情况下,我们将reloadCount设置为零,并将该值保存到localStorage
  2. 检测站点是否被重新加载或用户在较长时间后返回站点。 这是我们需要使用我们的lastUnloadAt值的地方。 为了检测站点是否确实被重新加载,我们需要将站点加载的时间(当前时间)与lastUnloadAt值进行比较。 如果这两个事件在例如五秒钟内发生(这完全是任意的),则表示用户重新加载了站点,我们应该运行重新加载计数逻辑。 如果这两个事件之间的时间间隔更长,我们重置reloadCount值。

有了这些,让我们创建一个名为checkReload的新函数,并将该逻辑保留在那里。

function checkReload() {
  if (localStorage.getItem("reloadCount")) {
    reloadCount = parseInt(localStorage.getItem("reloadCount"))
  } else {
    reloadCount = 0
    localStorage.setItem("reloadCount", reloadCount)
  }
  if (
    Math.floor(Date.now() / 1000) - localStorage.getItem("lastUnloadAt") <
    5
  ) {
    onReloadDetected()
  } else {
    reloadCount = 0;
    localStorage.setItem("reloadCount", reloadCount)
  }
}

在这一步中,我们需要创建的最后一个函数是一个负责当我们确认用户重新加载了站点时发生的事情的 method。 我们将该函数称为onReloadDetected,在其中,我们递增reloadCount的值。 如果用户第三次刷新站点,我们将按下炸弹并调用我们的logout逻辑。

function onReloadDetected() {
  reloadCount = reloadCount + 1
  localStorage.setItem("reloadCount", reloadCount)
  if (reloadCount === 3) {
    logout()
  }
}

步骤 3:“亲爱的用户,你为什么不听?!”

在这一步中,我们实现了负责用户重新加载站点的逻辑,尽管我们明确警告他们停止这样做,但他们还是重新加载了站点,直到超过了我们的三次限制阈值。

当这种情况发生时,我们调用我们的 API 注销用户,然后清理与重新加载计数逻辑相关的所有属性。 这将允许用户回来并获得重新加载的干净记录。 我们还可以将用户重定向到有用的地方,例如登录屏幕。(但将他们发送到这里不是很有趣吗?)

function logout(params) {
  // logout API call
  resetReloadCount()
}

function resetReloadCount() {
  window.removeEventListener("beforeunload", beforeUnloadHandler)
  localStorage.removeItem("lastUnloadAt")
  localStorage.removeItem("reloadCount");
}

奖励:让我们重新 Vue 它!

现在我们已经实现了逻辑,让我们看看如何将该逻辑移动到基于此示例的 Vue 站点

首先,我们需要将我们所有的变量移动到我们组件的data中,所有反应式道具都位于此。

export default {
  data() {
    return {
      reloadCount: 0,
      warningMessages: [...]
    }
  },

然后,我们将所有函数移动到methods

// ...
  methods: {
    beforeUnloadHandler() {...},
    checkReload() {...},
    logout() {...},
    onReloadDetected() {...},
    resetReloadCount() {...},
    initializeReloadCount() {...}
  }
// ...

由于我们使用的是 Vue 及其反应式系统,我们可以删除所有直接的 DOM 操作(例如document.getElementById("app").innerHTML),并依赖于我们的warningMessages数据属性。 为了显示正确的警告消息,我们需要添加一个计算属性,该属性将在每次我们的reloadCount发生变化时重新计算,以便我们可以从我们的warningMessages返回一个字符串。

computed: {
  warningMessage() {
    return this.warningMessages[this.reloadCount];
  }
},

然后,我们可以直接在组件的模板中访问我们的计算属性。

<template>
  <div id="app">
    <p>{{ warningMessage }}</p>
  </div>
</template>

我们需要做的最后一件事是找到一个适当的位置来激活重新加载阻止逻辑。 Vue 提供了组件生命周期钩子,这些钩子正是我们需要的,特别是created钩子。 让我们把它放进去。

// ...
  created() {
    this.initializeReloadCount();
  },
// ...

很好。

总结

这就是它,检查并计算页面刷新次数的逻辑。 希望您喜欢这段旅程,并且您发现此解决方案有用或至少鼓舞人心,可以做得更好。🙂