【问题标题】:mailto link (in chrome) is triggering window.onbeforeunload - can i prevent this?mailto 链接(在 chrome 中)正在触发 window.onbeforeunload - 我可以防止这种情况吗?
【发布时间】:2012-04-02 04:30:09
【问题描述】:

可能与How to open mailto link in Chrome with Window.open without creating a new tab?有关

大家好。我有一个表单页面,我在其中放置了一个 window.onbeforeunload 确认,以防止人们导航并意外丢失他们的更改:

window.onbeforeunload = function(){
  if(changed)
    return "You have unsaved changes.  Do you really want to leave this page without saving?";
};  

其中changed 是一个变量,我在用户进行任何更改时设置为true。没关系。但是,我还向页面添加了一些 mailto 链接,如下所示:

<a class="button button-alt" href="mailto:foo@foo.com">Report a problem</a>

即使 mailto 没有离开页面(它正在打开用户默认的邮件应用程序),它仍然会触发 onbeforeunload 事件,提示确认框,这很烦人。我可以绕过它在链接上设置target="_blank",但随后用户坐在一个空标签中。

我可以将 mailto 链接设置为不触发 onbeforeunload 事件吗?我想到了一种非常骇人听闻的方法,方法是使用另一个临时 javascript 变量,这会导致 onbeforeunload 确认不触发,但它似乎有点脏。无论如何我都会在等待回复时这样做,但有人有更好的解决方案吗?

谢谢,马克斯

【问题讨论】:

    标签: javascript mailto onbeforeunload


    【解决方案1】:

    解决这个问题的一个非常简单的方法是执行以下操作:

    <a href="mailto:foo@bar.com" target="hidden-iframe">Email me</a>
    <iframe name="hidden-iframe" style="visibility:hidden;position:absolute;"></iframe>
    

    (当然,将样式移动到它们自己的样式表中,而不是内联它们。)

    【讨论】:

    • 我参加聚会迟到了,但遇到了同样的问题。这是迄今为止更好的解决方案。其他的依赖于很多丑陋的 JavaScript/jQuery。通过这种方式,您可以使用零 JavaScript 在 html 模板中自包含修复。
    • @Oranges13:当然可以。你用的是什么版本?
    • 这在 Chrome 中为我工作,直到我添加了破坏它的“frame-src”CSP
    • 谢谢@JohnKurlak 这是一个很棒的解决方案。这只是刚刚从这篇旧帖子中受益的人的迟到回应。谢谢。
    • 这也是 Blazor 应用程序遇到与“tel:”链接断开连接问题的修复程序
    【解决方案2】:

    基于 epascarello 的解决方案,下面的 JQuery 代码应该可以解决问题:

        var ignore_onbeforeunload = false;
        $('a[href^=mailto]').on('click',function(){
            ignore_onbeforeunload = true;
        });
    
        window.onbeforeunload = function() {
            if (!ignore_onbeforeunload){
                return "Halt! you are not supposed to leave!";
            }
            ignore_onbeforeunload = false;
        };
    

    【讨论】:

    • 真的吗? 3年后你回复帖子?大声笑唯一的区别是添加带有不显眼的事件的点击...大声笑
    • 无缘无故依赖jQuery,依赖全局变量。约翰库拉克在下面的回答要好得多。它使用隐藏的 iframe,完全不需要 JavaScript,更不用说 jQuery。然后可以在模板文件中自包含修复。
    • 点击此类链接时不调用onbeforeunload的浏览器怎么办?在这种情况下,似乎将跳过关闭。
    • 问题是如何避免在触发时降低体验。不支持时正是理想的体验。
    【解决方案3】:

    加个flag,看是否翻转,在链接点击时设置flag。

    var ignore = false
    window.onbeforeunload = function() {
        if (changed && !ignore) {
            return "You have unsaved changes.  Do you really want to leave this page without saving?";
        } else {
            ignore = false;
        }
    }
    

    还有链接

    <a class="button button-alt" href="mailto:foo@foo.com" onclick="ignore=true">Report a problem</a>
    

    最好用 JavaScript 代码添加 onclick。

    【讨论】:

    • @MaxWilliams,点击此类链接时不调用onbeforeunload 的浏览器怎么办?在这种情况下,似乎将跳过关闭。
    • @epascarello 改变的变量是什么? (第 3 行)
    【解决方案4】:

    我通过检查 event.target 设法在 onbeforeunload 事件中解决了这个问题。这样您就不必使用外部变量或任何额外的绑定。

    window.onbeforeunload = function (event) {
    
        var activeElement = $(event.target.activeElement);
        // console.log('onbeforeunload', activeElement);
    
        var isMailto = activeElement && activeElement.is('[href^=mailto:]');
        var isTel = activeElement && activeElement.is('[href^=tel:]');
    
        if(!isMailto && !isTel) {
            // logic when link is "normal"
        }
    };
    

    【讨论】:

      【解决方案5】:

      另一个选项,也有点 hacky 但更通用的方法来使 beforeunload 忽略某些类型的链接:

      在 beforeunload 中,检查导致 beforeunload 的链接,如果不是 http 或 https 链接,请不要打扰用户。

      不幸的是,检查导致 beforeunload 的链接并不容易,所以这就是使用 onclick 处理程序和全局变量的地方。

      var lastClicked = null;
      window.onclick = function(e){
          e = e || window.event;
          lastClicked = e.target
      }
      window.onbeforeunload = function(e){
          if (changed && lastClicked && lastClicked.href 
              && lastClicked.href.substring(0,4) == 'http')
              return "You have unsaved changes";
      }
      

      编辑:差点忘了,这个答案来自这里:https://stackoverflow.com/a/12065766/421243

      【讨论】:

        【解决方案6】:

        使用纯 JS 并使用焦点元素的其他一些解决方案:

        window.addEventListener("beforeunload", () => {
          const isMailTo = document.activeElement.protocol === "mailto:";
        
          if (!isMailTo) {
            // do your stuff
          }
        });
        

        【讨论】:

          【解决方案7】:

          根据John Kurlak 的回答,您可以简单地使用:

          <a href="mailto:foo@bar.com" target="_blank">Email me</a>
          

          【讨论】:

            【解决方案8】:

            根据 Theiaz 的回答,您可以添加一个布尔全局变量 protectUnload 后跟一个正则表达式,以允许除链接 ( http(s) ) 之外的所有外部协议:

            window.onbeforeunload = function (event) {
                return (protectUnload && (typeof document.activeElement.protocol !== "undefined" && /^http(s)?:$/.test(document.activeElement.protocol))) || null; // return null == no confirm
            };
            

            它不会阻止使用 location.href 从页面中踢出,但在这种情况下,您可以在公式中再添加 1 个布尔值,以始终保护卸载页面(在 @987654325 之前将其设置为 true @ 的新值)。

            【讨论】:

            • 添加布尔全局变量通常不是最有力的答案。将您的 JS 包含在 IIFE 或类似范围的属性中是正确的方法。这篇已有近 9 年历史的帖子中的其他答案很好地处理了这个问题。
            【解决方案9】:

            将锚点的目标设置为隐藏在页面中的隐藏 iframe。 &lt;a href="mailto:x@y.com" target="hiddenIframe".

            如果通过 javascript 函数(从按钮或锚点或其他)调用 mailto,您甚至可以动态创建 iframe,将其 src 设置为 mailto,然后在超时时将其删除。

            无论哪种方式,当前页面都不受影响,也不需要弹出标签或窗口。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-03-28
              • 2016-12-16
              • 1970-01-01
              • 2018-02-16
              • 1970-01-01
              • 2019-06-12
              • 1970-01-01
              • 2016-09-12
              相关资源
              最近更新 更多