如何在我的网站上提供所有外部链接提出确认

时间:2018-06-08 14:23:15

标签: javascript html angularjs

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

4 个答案:

答案 0 :(得分:2)

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

&#13;
&#13;
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
    }
}
&#13;
<a href="/foo/bar">internal</a>
<a href="https://example.com">external</a>

<a href="https://stacksnippets.net/js">also internal</a>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

由于您使用的是Angular.js,我建议您查看它们如何与<a>一起使用,因为已经已将指令应用于所有<a> ngHref工作。来源将在这里:<a> directive

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

因为Angular.js已经定义了一个<a>指令,你可能需要摆弄你指令的priority,这样你才不会意外地破坏它方式Angular与<a>混合。

该指令看起来像这样:

// 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
                    }
                });
            }
        }
    });

答案 2 :(得分:0)

  1. 可以通过正则表达式匹配来实现。
  2. 可以在document对象上添加单个事件侦听器,而不是添加多个事件侦听器,并按如下方式检测外部链接。它会提高效率。
  3. 供参考,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>

    感谢regex的@pseudosavant。

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

答案 3 :(得分:0)

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