使用jQuery / JavaScript测试链接是否为外部链接?

76

如何测试链接是否为外部链接或内部链接?请注意:

  1. 我不能硬编码本地域名。
  2. 我不能测试"http"。我可能会使用http绝对链接链接到自己的网站。
  3. 我想使用jQuery / javascript,而不是css。

我怀疑答案在location.href中,但解决方案让我无从下手。

谢谢!


你想在链接被点击时检查它还是在页面加载时检查它? - Elangovan
17个回答

74

我知道这篇文章很旧了,但它仍然出现在搜索结果的顶部,所以我想提供另一种方法。我看到有关锚元素的所有正则表达式检查,但为什么不只是使用window.location.host并检查该元素的host属性?

function link_is_external(link_element) {
    return (link_element.host !== window.location.host);
}

使用jQuery:

$('a').each(function() {
    if (link_is_external(this)) {
        // External
    }
});

并且可以使用纯Javascript:

var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++) {
    if (link_is_external(links[i])) {
        // External
    }
}

8
这是我唯一能理解的答案 - 其他答案都过于复杂。这种方法有没有任何反对意见? - tremby
上面的jQuery在Safari中对我有效,并处理了其他所有问题 - 本地锚点,相对URL,跨协议URL等。注意:http://www.example.com和https://www.example.com将被标记为内部链接;这可能对您很重要。 - Mark
1
这是最好的答案。它利用了a.host属性,这个属性可能对于普通的JavaScript开发人员来说是未知的(包括我在内,在读到这篇文章之前)。 - dana
1
当指定端口号时,此操作将失败,同时如果省略“www”,也会失败。 - Andrew
1
我有点晚了,但我想对@Andrew说,“www”是一个标识符,可以指示不同的匹配。虽然域名可能相同,但使用WWW时主机会有所不同,我认为这是一个有效的条件。如果它们都!=“”,端口也可以通过使用“.port”比较来检查。 - Daved
显示剩余5条评论

66
var comp = new RegExp(location.host);

$('a').each(function(){
   if(comp.test($(this).attr('href'))){
       // a link that contains the current host           
       $(this).addClass('local');
   }
   else{
       // a link that does not contain the current host
       $(this).addClass('external');
   }
});
注意:这只是一个快速而简单的示例。它也会将所有href =“#anchor”的链接视为外部链接。通过执行一些额外的RegExp检查,可以改进它。
更新2016-11-17

这个问题仍然有很多访问量,并且有很多人告诉我这个被接受的解决方案会在几种情况下失败。正如我所说的,这是一个非常快速而简单的答案,以展示解决此问题的主要方法。更复杂的解决方案是使用在<a>(锚点)元素上可访问的属性。就像@Daved已经在这个答案中指出的那样,关键是将hostname与当前window.location.hostname进行比较。我更喜欢比较hostname属性,因为如果端口不同于80,则host属性将包括端口。

所以我们来做到这一点:
$( 'a' ).each(function() {
  if( location.hostname === this.hostname || !this.hostname.length ) {
      $(this).addClass('local');
  } else {
      $(this).addClass('external');
  }
});

最先进的技术:

Array.from( document.querySelectorAll( 'a' ) ).forEach( a => {
    a.classList.add( location.hostname === a.hostname || !a.hostname.length ? 'local' : 'external' );
});

7
我相信使用相对URL这种方式是不可行的。attr应该返回属性而不是属性值(属性值可能会被解析,但并不属于属性)。 - Sean Kinsey
10
这种方法不适用于相对网址,已经得到验证。 - Sean Kinsey
4
如果您使用 href 属性而不是 href 属性,则相对路径也可以起作用。 - Kevin B
2
我看到仍有人查看这个问题和解决方案,所以我想在下面链接到我的建议解决方案,它应该处理所有检查而不需要使用正则表达式或相关问题:https://dev59.com/BnE85IYBdhLWcg3wKwSE#18660968 - Daved
1
更新的答案。 - jAndy
显示剩余9条评论

37

还有一种无需使用jQuery的方法

var nodes = document.getElementsByTagName("a"), i = nodes.length;
var regExp = new RegExp("//" + location.host + "($|/)");
while(i--){
    var href = nodes[i].href;
    var isLocal = (href.substring(0,4) === "http") ? regExp.test(href) : true;
    alert(href + " is " + (isLocal ? "local" : "not local"));
}

所有以http(http://、https://)开头之外的href都会自动视为本地链接。


1
这个答案更准确。相对URL也很重要。 - Savageman
如果我没记错的话,"($|/" 应该是 "($|/)",需要加上一个闭括号。 - Grimace of Despair
2
这个解决方案很接近,但你还应该检查href属性是否以 location.protocol+'//'+location.host 开头。 请查看此fiddle:http://jsfiddle.net/framp/Ag3BT/1/ - framp
2
你为什么要用while循环来做这件事?在我看来,使用事件委托通过$(document).on('click', 'a', function({});测试被点击的特定链接(在被点击的时候)会更有意义。这样,你就不需要无谓地遍历页面上的所有链接,并且它将允许在初始DOM准备之后通过ajax添加到页面上的任何元素...有时候使用jQuery是有意义的(超越了“粉丝”的范畴)。 - 1nfiniti
7
如果您使用协议不可知的URL(即href="//somedomain.com/some-path"),这种方法将无法正常工作。 - rossipedia

9
var external = RegExp('^((f|ht)tps?:)?//(?!' + location.host + ')');

使用方法:

external.test('some url'); // => true or false

1
+1 对于正则表达式的建议,虽然它并不能完全解决这个问题。 - feeela

7
这是一个仅选择外部链接的jQuery选择器:
$('a[href^="(http:|https:)?//"])') 

一个仅适用于内部链接(不包括同一页内的哈希链接)的jQuery选择器需要更加复杂:

$('a:not([href^="(http:|https:)?//"],[href^="#"],[href^="mailto:"])')

可以在:not()条件内添加其他过滤器,并根据需要用逗号分隔。

http://jsfiddle.net/mblase75/Pavg2/


或者,我们可以使用原生JavaScript的href属性来过滤内部链接,它始终是绝对URL:

$('a').filter( function(i,el) {
    return el.href.indexOf(location.protocol+'//'+location.hostname)===0;
})

http://jsfiddle.net/mblase75/7z6EV/


+1:好的,有一种方式可以再次为您的回答点赞 :) - iCollect.it Ltd
第一个不起作用,因为“//code.jquery.com/jquery.min.js”是完全合法的URL,但不是内部URL。协议和冒号不是必需的,因为浏览器将使用当前站点正在使用的任何内容(一种半协议相对URL)。 - mikesir87
提醒一下,您的外部选择器出现了错误:Uncaught Error: Syntax error, unrecognized expression: a[href^="(http:|https:)?//"]) - kthornbloom

6
您忘了一种情况,就是当您使用相对路径的时候。
例如: /test
        hostname = new RegExp(location.host);
            // Act on each link
            $('a').each(function(){

            // Store current link's url
            var url = $(this).attr("href");

            // Test if current host (domain) is in it
            if(hostname.test(url)){
               // If it's local...
               $(this).addClass('local');
            }
            else if(url.slice(0, 1) == "/"){
                $(this).addClass('local'); 
            }
            else if(url.slice(0, 1) == "#"){
                // It's an anchor link
                $(this).addClass('anchor'); 
            }
            else {
               // a link that does not contain the current host
               $(this).addClass('external');                        
            }
        });

还有文件下载的问题,即.zip文件(本地或外部),可以使用“本地下载”或“外部下载”类。但是目前还没有找到解决方案。


并非所有相对URL都以“/”开头。您可以引用类似于images/logo.png的内容,该内容比当前位置低一个文件夹。在这种情况下,您正在引用相对URL中的相对路径,在站点的不同目录中具有不同的含义。/images/logo.png是运行在任何网站上的绝对路径(因此是相对的)。您的代码将不包括像images/logo.png这样的相对路径。 - Adam Plocher

6
const isExternalLink = (url) => {
    const tmp = document.createElement('a');
    tmp.href = url;
    return tmp.host !== window.location.host;
};

// output: true
console.log(isExternalLink('https://foobar.com'));
console.log(isExternalLink('//foobar.com'));

// output: false
console.log(isExternalLink('https://www.stackoverflow.com'));
console.log(isExternalLink('//www.stackoverflow.com'));
console.log(isExternalLink('/foobar'));
console.log(isExternalLink('#foobar'));

使用这种方法的好处是:
  • 它会自动解析相对路径和片段的hostname
  • 它可以与“协议相对”URL一起使用。
为了证明这一点,让我们看一下以下例子:
const lnk = document.createElement('a');
lnk.href = '/foobar';

console.log(lnk.host); // output: 'www.stackoverflow.com'

const lnk = document.createElement('a');
lnk.href = '#foobar';

console.log(lnk.host); // output: 'www.stackoverflow.com'

const lnk = document.createElement('a');
lnk.href = '//www.stackoverflow.com';

console.log(lnk.host); // output: 'www.stackoverflow.com'

4

使用jQuery

jQuery('a').each(function() {
    if (this.host !== window.location.host) {
        console.log(jQuery(this).attr('href'));
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


2
一个好的答案总是会包括解释为什么这样做可以解决问题,这样原帖作者和任何未来的读者都可以从中学习。 - Tyler2P

3
你可以使用 is-url-external 模块。
var isExternal = require('is-url-external');
isExternal('https://dev59.com/BnE85IYBdhLWcg3wKwSE'); // true | false 

2

这应该适用于除IE浏览器外的任何浏览器上的任何链接。

// check if link points outside of app - not working in IE
                try {
                    const href = $linkElement.attr('href'),
                        link = new URL(href, window.location);

                    if (window.location.host === link.host) {
                        // same app
                    } else {
                        // points outside
                    }
                } catch (e) { // in case IE happens}

请注意 new URL(href, window.location):类型为'Location'的参数不能赋值给类型为'string | URL | undefined'的参数。 - Cezary Tomczyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接