【问题标题】:How to have all external links on my website raise a confirm如何让我网站上的所有外部链接得到确认
【发布时间】:2018-11-18 15:20:07
【问题描述】:

我正在尝试让我网站上的所有外部链接都发出确认消息“您正在被重定向到外部网站”。我知道如何编写 JS 来检查链接是否是外部的以及如何提高确认,但是有没有一种方法可以将其应用于我网站中的每个链接而无需单独执行?链接的格式始终为<a href=URL> Link </a>。角度脚本会检查URL 子域是否与我的站点相同,如果不是,它将添加onclick=return confirm('You will now be redirected to an exteral site')target="_blank" 到链接HTML。

【问题讨论】:

  • 是的,你试过什么?
  • @Luca 我真的不知道从哪里开始。我试过谷歌搜索,但还没有找到任何适用的东西。
  • 就目前而言,我认为您的问题可能过于广泛。我认为您的下一步是定义要保护用户的位置的上下文。有 很多 种方法可以更改页面。您可以控制一些,例如包装<a> 点击,但如果您的页脚链接不断触发警告,它可能会令人恼火。您的网站是否基于用户内容?你只想警告那些吗?用户在帖子中是否仅限于<a>s?上下文是什么?
  • @zero298 我已经更新了更多信息。
  • 如果您要触发警告的链接具有该指令,那么什么不起作用?您想将此保护扩展到没有该指令的链接吗?

标签: javascript html angularjs


【解决方案1】:

正如您已经说过的,这可以通过使用confirm onclick 来实现,您可以轻松地将 EventListener 添加到页面中所有外部 (l.hostname !== location.hostname) 的 a 元素中,并且仅在用户接受后重定向消息,就像这样:

Array.from(document.querySelectorAll("a")).filter(l => l.hostname !== location.hostname).forEach(el => el.addEventListener("click", evtL));

function evtL(e) {
    if (confirm("Are you sure you want to leave the page?")) {
      return; //redirect
    } else {
      e.preventDefault();
      return false; //don't redirect
    }
}
<a href="/foo/bar">internal</a>
<a href="https://example.com">external</a>

<a href="https://stacksnippets.net/js">also internal</a>

【讨论】:

  • 我在您发布您的答案的同时写我的评论,所以我看不到它。为什么不过滤 querySelectorAll 的结果,所以不是所有的链接都有一个 eventListener,而只有那些需要有的?
  • 你说得对,这样会更有效率,谢谢建议
  • 编辑了我的帖子!
【解决方案2】:
  1. 可以通过正则匹配来实现。
  2. 可以在document对象上添加单个事件侦听器,而不是添加多个事件侦听器,并如下检测外部链接。这将提高效率。

供参考,Handling events for multiple elements in a single listener

var regexp = /https?:\/\/(www.){0,1}((?:[\w\d-]+\.)+[\w\d]{2,})/i;
function isExternal(url)
{
    return regexp.exec(location.href)[2] !== regexp.exec(url)[2];
}

document.addEventListener("click",function(){
    if(event.target.tagName.toLowerCase()==="a")
    {
        if(isExternal(event.target.href))
        {
            if(confirm("Redirecting to an external site...."))
            {
                console.log("Going to external site...");
                return;
            }
            else
            {
                event.preventDefault();
                return;
            }
        }
        else
        {
            console.log("Internal URL Clicked.")
        }
    }
});
<a href="https://www.google.com" target="_blank">External Site 1</a> - https://www.google.com<br>
<a href="https://www.stackoverflow.com" target="_blank">External Site 2</a> - https://www.stackoverflow.com<br>
<a href="http://www.facebook.com" target="_blank">External Site 3</a> - http://www.facebook.com (Using HTTP)<br>
<a href="http://www.stacksnippets.net" target="_blank">Internal Site (Using HTTP)</a> - http://www.stacksnippets.net<br>
<a href="http://stacksnippets.net" target="_blank">Internal Site (without www.)</a> - http://stacksnippets.net<br>
<a href="/path/to/something" target="_blank">Internal reference</a> - /path/to/something (Internal reference)<br>

感谢@pseudosavant 提供regex

虽然@Luca 的回答有效,但 IE、Safari 和 Opera 不支持 hostnameBrowser Compatibility供参考。

【讨论】:

  • 谢谢。我最终使用了我自己的逻辑而不是你的正则表达式,但它起作用了。如果用户确实确认他或她想离开,我该如何添加target="blank"
  • 找不到你。你的意思是如果用户确认,你想将用户引导到新标签中的另一个页面?
  • 是的。填料填料
  • 已经可以了,对吧?它的 target="_blank"(带有下划线)。
  • 我希望能够不必在原始html中指定
【解决方案3】:

由于您使用的是 Angular.js,我建议您看看它们如何与 &lt;a&gt; 一起工作,因为它们已经有一个指令应用于所有 &lt;a&gt; 以使 ngHref 工作.来源在这里:&lt;a&gt; directive

基本思想是将用于将href 更改为警告或显示模式或其他任何内容的逻辑放在element.on('click', function(event) {...}) 中。

由于 Angular.js 已经定义了一个 &lt;a&gt; 指令,您可能需要摆弄指令的 priority,以免意外破坏 Angular 摆弄 @987654331 的方式@。

指令看起来像这样:

// Logic that dictactes whether the URL should show a warning
function isSuspectUrl(l) {
    return false;
}

const app = angular
    .module("aWarn", [])
    .directive("a", function() {
        return {
            restrict: "E",
            compile: function(el, attr) {
                element.on("click", function(e) {
                    if (isSuspectUrl(attr.href)) {
                        // Logic that would display a warning
                    }
                });
            }
        }
    });

【讨论】:

    【解决方案4】:

    2021 版

    • es2015+
    • 与 SPA 配合使用
    • 处理看似外部的本地链接
    • 子域支持

    const baseUrl = window.location.origin;
    const absoluteUrlRegex = new RegExp('^(?:[a-z]+:)?//', 'i');
    
    const isAbsoluteUrl = (url) => absoluteUrlRegex.test(url);
    const isLocalUrl = (url) => url.startsWith(baseUrl) || !isAbsoluteUrl(url);
    
    // https://gist.github.com/ -> github.com
    // https://stackoverflow.com/ -> stackoverflow.com
    const getDomain = (url) => {
        const urlInstance = new URL(url);
        const dividedUrl = urlInstance.hostname.split('.');
        const urlDomainsCount = dividedUrl.length;
        return urlDomainsCount === 2
            ? urlInstance.hostname
            : `${dividedUrl[urlDomainsCount - 2]}.${dividedUrl[urlDomainsCount - 1]}`;
    };
    
    // example whitelist
    const whitelist = [
        'twitter.com',
        'github.com',
    ];
    
    // url has same domain or whitelisted
    const isWhitelistedUrl = (url) => {
        const domain = getDomain(url);
        return domain === window.location.hostname || whitelist.includes(domain);
    };
    
    // bind listener
    const confirmExternalLinks = (confirmationFn) => {
        document.addEventListener('click', async (e) => {
            const linkElement = e.target.closest('a');
            if (!linkElement) return;
            const link = linkElement.getAttribute('href');
            if (isLocalUrl(link) || isWhitelistedUrl(link)) return;
            e.preventDefault();
            const confirmation = await confirmationFn(link);
            if (confirmation) window.open(link);
        });
    };
    
    // tip: replace confirmationFn with your custom handler which returns Promise
    confirmExternalLinks((link) => confirm(`Proceed to ${link}?`));
    <a target="_blank" href="https://stacksnippets.net/">https://stacksnippets.net/</a>  is local for this snippet iframe
    <br>
    <a target="_blank" href="https://twitter.com/">https://twitter.com/</a> is whitelisted
    <br>
    <a target="_blank" href="https://developer.mozilla.org/">https://developer.mozilla.org/</a>  is external

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      相关资源
      最近更新 更多