用 jQuery/javascript 测试链接是否是外部的?

如何测试链接是外部的还是内部的? 请注意:

  1. 我不能硬编码本地域。
  2. 我不能测试“ http”。我可以很容易地链接到我自己的网站与 http 绝对链接。
  3. 我想使用 jQuery/javascript,而不是 css。

我怀疑答案就在某个地方,但是答案逃避了我。

谢谢!

51263 次浏览

是的,我相信您可以使用 location.href 检索当前域名。另一种可能性是创建一个 link 元素,将 src 设置为/,然后检索规范 URL (如果使用的话,这将检索基 URL,但不一定是域名)。

也可以看看这篇文章: 从链接的 href 属性获取完整的 URI

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 = “ # 锚”链接 它可以通过执行一些额外的 RegExp 检查来改进。


更新2016-11-17

这个问题仍然得到了很多的流量,我被告知,一吨的人,这个公认的解决方案将在几个场合失败。正如我所说,这是一个非常快速和肮脏的答案,显示了如何解决这个问题的主要方法。一个更复杂的解决方案是使用可在 <a>(锚)元素上访问的属性。就像@Dave 在这个答案中已经指出的那样,关键是将 hostname与当前的 window.location.hostname进行比较。我更愿意比较 hostname的属性,因为他们从来没有包括 port是包括到 host的属性,如果它不同于80。

我们开始吧:

$( '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' );
});

还有不用 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 都被自动视为本地的

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

用法:

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

你忘了一个,如果你使用相对路径。

例子:/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');
}
});

还有文件下载的问题。它可以使用类“本地下载”或“外部下载”。但还没找到解决办法。

我知道这篇文章很老了,但它仍然显示在结果的顶部,所以我想提供另一种方法。我看到了对锚元素的所有正则表达式检查,但是为什么不使用 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
}
}

这里有一个只针对外部链接的 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/

对于那些感兴趣的人,我做了一个 if 块的三元版本,检查元素有哪些类以及附加了哪些类。

$(document).ready(function () {
$("a").click(function (e) {


var hostname = new RegExp(location.host);
var url = $(this).attr("href");


hostname.test(url) ?
$(this).addClass('local') :
url.slice(0, 1) == "/" && url.slice(-1) == "/" ?
$(this).addClass('localpage') :
url.slice(0, 1) == "#" ?
$(this).addClass('anchor') :
$(this).addClass('external');


var classes = $(this).attr("class");


console.log("Link classes: " + classes);


$(this).hasClass("external") ? googleAnalytics(url) :
$(this).hasClass("anchor") ? console.log("Handle anchor") : console.log("Handle local");


});
});

谷歌分析位可以被忽略,但这是你可能想做一些与网址,现在你知道什么类型的链接。只需在三进制块中添加代码。 如果您只想检查1种类型的链接,那么用 If 语句替换三元组。

编辑加入了我碰到的一个问题。我的一些厨师是这样说的。我检查了一个 localpage,它检查 href 的开头和结尾是否有一个斜杠。尽管在开头检查’/’可能就足够了。

可以使用 是外部的模块。

var isExternal = require('is-url-external');
isExternal('http://stackoverflow.com/questions/2910946'); // true | false

我将这个函数用于 jQuery:

$.fn.isExternal = function() {
var host = window.location.host;
var link = $('<a>', {
href: this.attr('href')
})[0].hostname;
return (link !== host);
};

用法是: $('a').isExternal();

例子: https://codepen.io/allurewebsolutions/pen/ygJPgV

/**
* All DOM url
* [links description]
* @type {[type]}
*/
var links = document.querySelectorAll('a');
/**
* Home Page Url
* [HomeUrl description]
* @type {[type]}
*/
var HomeUrl = 'https://stackoverflow.com/'; // Current Page url by-> window.location.href


links.forEach(function(link) {
link.addEventListener('click', function(e) {
e.preventDefault();


// Make lowercase of urls
var url = link.href.toLowerCase();
var isExternalLink = !url.includes(HomeUrl);


// Check if external or internal
if (isExternalLink) {
if (confirm('it\'s an external link. Are you sure to go?')) {
window.location = link.href;
}
} else {
window.location = link.href;
}
})
})
<a href="https://stackoverflow.com/users/3705299/king-rayhan">Internal Link</a>
<a href="https://wordpress.stackexchange.com/">External Link</a>

这应该适用于除 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}

这并不完全符合“不能硬编码我的领域”的先决条件的问题,但我发现这篇文章搜索类似的解决方案,在我的情况下,我 可以硬编码我的网址。我的担心是提醒用户,他们正在离开该网站,但如果他们留在现场就不会, 包括子域 (例如: blog.mysite.com,在其他大多数答案中都会失败)。所以我的解决方案是,从以上最受欢迎的答案中摘录一些内容:

Array.from( document.querySelectorAll( 'a' ) ).forEach( a => {
a.classList.add( a.hostname.includes("mywebsite.com") ? 'local' : 'external' );
});


$("a").on("click", function(event) {
if ($(this).hasClass('local')) {
return;
} else if ($(this).hasClass('external')) {
if (!confirm("You are about leave the <My Website> website.")) {
event.preventDefault();
}
}
});

用 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>

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的相对路径和片段;
  • 它与 protocol-relative 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'

这对我有用:

function strip_scheme( url ) {
return url.replace(/^(?:(?:f|ht)tp(?:s)?\:)?\/\/(www\.)?/g, '');
}


function is_link_external( elem ) {
let domain = strip_scheme( elem.attr('href') );
let host = strip_scheme( window.location.host );


return ! domain.indexOf(host) == 0;
}