当页面在 IE11 中冻结时,如何防止触发 OnBlur 事件

How can I prevent the OnBlur event from triggering when the page freezes in IE11

我有一个使用 React 的考试申请。我需要在 IE11 中 运行 这个应用程序。在此考试应用程序中,我添加了 onblur 事件,当用户离开选项卡时,该事件将 运行 触发,当此事件被触发时,用户会收到弹出窗口提醒,并且用户在 DB 中的 lockCount 会增加。如果 LockCount 超过为考试定义的限制,用户的考试将被阻止。

问题是当页面暂时冻结时会触发 onblur 事件。通常,当重新呈现页面或调用任何 API 服务需要很长时间时,就会出现此冻结问题。它在 Chrome.

中没有任何问题

我还尝试了 onBlur 事件和 Mouseleave 事件,但是当页面冻结时,mouseleave 事件也会触发。

如何防止在IE11中页面冻结时触发onBlur事件?

onBlur 和 onFocus 事件的代码:

  const onFocus = () => {
    setIsOnblur(false);
  };

  const onBlur = () => {
    increaseCount();
    setIsOnblur(true);
  };

  useEffect(() => {
    if (props.location.pathname.includes("/Exam/")) {
      window.addEventListener("focus", onFocus);
      window.addEventListener("blur", onBlur);

      return () => {
        window.removeEventListener("focus", onFocus);
        window.removeEventListener("blur", onBlur);
      };
    }
  }, []);

问题似乎是 blur 侦听器有时会在页面完全加载之前触发。我们可以通过 load 事件确定页面已完全加载。

来自MDN

The load event is fired when the whole page has loaded, including all dependent resources such as stylesheets and images.

因此,我会让 addEventListener 依赖于 window 是否已满载。这样的事情应该有效:

useEffect(() => {
  window.addEventListener("load", () => {
    if (props.location.pathname.includes("/Exam/")) {
      window.addEventListener("focus", onFocus);
      window.addEventListener("blur", onBlur);
    }

    return () => {
      window.removeEventListener("focus", onFocus);
      window.removeEventListener("blur", onBlur);
    };
  });
}, []);

我用这个()答案解决了这个问题。 This answer告诉您可以使用3种不同的方法来检测用户从网页上失去焦点。

  1. 页面可见度API
  2. Focus/Blur 事件
  3. 用户活动

就我而言,我解决了用户鼠标 activity 和超时的问题。

第一种情况:当用户将屏幕从网页完全切换到另一个页面或其他内容时,它会起作用。页面可见性 API 允许我们检测页面何时对用户隐藏。当页面最小化但页面未完全隐藏时,它不会捕获丢失的焦点。不算。

第二种情况:Focus-Blur 事件在正常情况下运行良好。但 Internet Explorer 问题误导了这一点。

第三种情况:由于上述问题,鼠标事件(mouseout、mousein、mouseover)不工作。但是如果我使用所有事件,尤其是鼠标事件超时,onBlur 事件不会在页面冻结时触发。

代码如下:

useEffect(() => {
    if (props.location.pathname.includes("/Exam/")) {
      var doc = document as any;

      // register to the W3C Page Visibility API
      var hidden: any = null;
      var visibilityChange: any = null;
      if (typeof doc.mozHidden !== "undefined") {
        hidden = "mozHidden";
        visibilityChange = "mozvisibilitychange";
      } else if (typeof doc.msHidden !== "undefined") {
        hidden = "msHidden";
        visibilityChange = "msvisibilitychange";
      } else if (typeof doc.webkitHidden !== "undefined") {
        hidden = "webkitHidden";
        visibilityChange = "webkitvisibilitychange";
        // } else if (typeof document.hidden !== "hidden") {
      } else if (doc.hidden) {
        hidden = "hidden";
        visibilityChange = "visibilitychange";
      }
      if (hidden != null && visibilityChange != null) {
        addEvent(doc, visibilityChange, function (event: any) {
          if (doc[hidden]) {
            onBlur();
          }
        });
      }

      // register to the potential page visibility change
      addEvent(doc, "potentialvisilitychange", function (event: any) {
        if (doc.potentialHidden && !doc[hidden]) {
          onBlur();
        }
      });

      var potentialPageVisibility = {
        pageVisibilityChangeThreshold: 3 * 3600, // in seconds
        init: function () {
          var lastActionDate: any = null;
          var hasFocusLocal: any = true;
          var hasMouseOver: any = true;
          doc.potentialHidden = false;
          doc.potentiallyHiddenSince = 0;
          var timeoutHandler: any = null;

          function setAsNotHidden() {
            var dispatchEventRequired = doc.potentialHidden;
            doc.potentialHidden = false;
            doc.potentiallyHiddenSince = 0;
            if (dispatchEventRequired) dispatchPageVisibilityChangeEvent();
          }

          function initPotentiallyHiddenDetection() {
            if (!hasFocusLocal) {
              // the window does not has the focus => check for  user activity in the window
              lastActionDate = new Date();
              if (timeoutHandler != null) {
                clearTimeout(timeoutHandler);
              }
              timeoutHandler = setTimeout(checkPageVisibility, potentialPageVisibility.pageVisibilityChangeThreshold * 1000 + 100); // +100 ms to avoid rounding issues under Firefox
            }
          }

          function dispatchPageVisibilityChangeEvent() {
            var evt = doc.createEvent("Event");
            evt.initEvent("potentialvisilitychange", true, true);
            doc.dispatchEvent(evt);
          }

          function checkPageVisibility() {
            var potentialHiddenDuration = (hasFocusLocal || lastActionDate == null ? 0 : Math.floor((new Date().getTime() - lastActionDate.getTime()) / 1000));
            doc.potentiallyHiddenSince = potentialHiddenDuration;
            if (potentialHiddenDuration >= potentialPageVisibility.pageVisibilityChangeThreshold && !doc.potentialHidden) {
              // page visibility change threshold raiched => raise the even
              doc.potentialHidden = true;
              dispatchPageVisibilityChangeEvent();
            }
          }
          addEvent(doc, "mousemove", function (event: any) {
            lastActionDate = new Date();
          });
          addEvent(doc, "mouseover", function (event: any) {
            hasMouseOver = true;
            setAsNotHidden();
          });
          addEvent(doc, "mouseout", function (event: any) {
            hasMouseOver = false;
            initPotentiallyHiddenDetection();
          });
          addEvent(window, "blur", function (event: any) {
            hasFocusLocal = false;
            initPotentiallyHiddenDetection();
          });
          addEvent(window, "focus", function (event: any) {
            hasFocusLocal = true;
            setAsNotHidden();
          });
          setAsNotHidden();
        }
      }

      potentialPageVisibility.pageVisibilityChangeThreshold = 1; // 4 seconds for testing
      potentialPageVisibility.init();
    }
}, []);