foo='http://john.doe'
が外部であるかどうかを検出する最も速い方法は何ですか rl (window.location.href
と比較して)?
正規表現バージョンがすでに受け入れられていることは知っていますが、これは、その複雑な正規表現を実行するよりも「高速」であるに違いありません。 String.replace
は非常に高速です。
var isExternal = function(url) {
var domain = function(url) {
return url.replace('http://','').replace('https://','').split('/')[0];
};
return domain(location.href) !== domain(url);
}
私はこれについてもう少し調査することに決め、正規表現を使用するより高速な方法を見つけました。
var isExternalRegexClosure = (function(){
var domainRe = /https?:\/\/((?:[\w\d-]+\.)+[\w\d]{2,})/i;
return function(url) {
function domain(url) {
return domainRe.exec(url)[1];
}
return domain(location.href) !== domain(url);
}
})();
IEこれはString.replace
メソッドよりもわずかに高速です。ただし、ChromeおよびFirefoxでは約2倍高速です。また、正規表現を定義するFirefoxでは、通常、関数内ではなくクロージャ内で1回だけ高速になります。
これはjsperfです 外部ホスト名を決定する4つの異なる方法を調べます。
私が試したすべてのメソッドは、古い電話でも実行するのに1ms未満かかることに注意することが重要です。したがって、大規模なバッチ処理を行わない限り、パフォーマンスを主な考慮事項にするべきではありません。
スキーム、ホスト、またはポートのいずれかが異なる場合にURLが外部であると考える場合は、次のようにすることができます。
function isExternal(url) {
var match = url.match(/^([^:\/?#]+:)?(?:\/\/([^\/?#]*))?([^?#]+)?(\?[^#]*)?(#.*)?/);
if (typeof match[1] === "string" && match[1].length > 0 && match[1].toLowerCase() !== location.protocol) return true;
if (typeof match[2] === "string" && match[2].length > 0 && match[2].replace(new RegExp(":("+{"http:":80,"https:":443}[location.protocol]+")?$"), "") !== location.Host) return true;
return false;
}
私はpsuedosavantの方法を使用してきましたが、ドメインのないリンク(_/about
_、_image.jpg
_)やアンカーリンク(_#about
_)など、誤検知が発生するケースがいくつか発生しました。古い方法では、プロトコルが異なると結果も不正確になります(http
vs https
)。
これが私のわずかに変更されたバージョンです:
_var checkDomain = function(url) {
if ( url.indexOf('//') === 0 ) { url = location.protocol + url; }
return url.toLowerCase().replace(/([a-z])?:\/\//,'$1').split('/')[0];
};
var isExternal = function(url) {
return ( ( url.indexOf(':') > -1 || url.indexOf('//') > -1 ) && checkDomain(location.href) !== checkDomain(url) );
};
_
更新された関数を使用したいくつかのテストを次に示します。
_isExternal('http://google.com'); // true
isExternal('https://google.com'); // true
isExternal('//google.com'); // true (no protocol)
isExternal('mailto:[email protected]'); // true
isExternal('http://samedomain.com:8080/port'); // true (same domain, different port)
isExternal('https://samedomain.com/secure'); // true (same domain, https)
isExternal('http://samedomain.com/about'); // false (same domain, different page)
isExternal('HTTP://SAMEDOMAIN.COM/about'); // false (same domain, but different casing)
isExternal('//samedomain.com/about'); // false (same domain, no protocol)
isExternal('/about'); // false
isExternal('image.jpg'); // false
isExternal('#anchor'); // false
_
いくつかの基本的な jsperfテスト によれば、全体的にはより正確であり、最終的にはわずかに高速になります。大文字と小文字を区別しないテストのために.toLowerCase()
を省略した場合、さらに高速化できます。
pseudosavantの答えは私には正確に機能しなかったので、私はそれを改善しました。
var isExternal = function(url) {
return !(location.href.replace("http://", "").replace("https://", "").split("/")[0] === url.replace("http://", "").replace("https://", "").split("/")[0]);
}
「//」で始まるURLやサブドメインを含まないURLのケースもキャッチする必要があったため、pseudosavantとJonの回答に基づいて構築する必要がありました。これが私のために働いたものです:
var getDomainName = function(domain) {
var parts = domain.split('.').reverse();
var cnt = parts.length;
if (cnt >= 3) {
// see if the second level domain is a common SLD.
if (parts[1].match(/^(com|edu|gov|net|mil|org|nom|co|name|info|biz)$/i)) {
return parts[2] + '.' + parts[1] + '.' + parts[0];
}
}
return parts[1]+'.'+parts[0];
};
var isExternalUrl = function(url) {
var curLocationUrl = getDomainName(location.href.replace("http://", "").replace("https://", "").replace("//", "").split("/")[0].toLowerCase());
var destinationUrl = getDomainName(url.replace("http://", "").replace("https://", "").replace("//", "").split("/")[0].toLowerCase());
return !(curLocationUrl === destinationUrl)
};
$(document).delegate('a', 'click', function() {
var aHrefTarget = $(this).attr('target');
if(typeof aHrefTarget === 'undefined')
return;
if(aHrefTarget !== '_blank')
return; // not an external link
var aHrefUrl = $(this).attr('href');
if(aHrefUrl.substr(0,2) !== '//' && (aHrefUrl.substr(0,1) == '/' || aHrefUrl.substr(0,1) == '#'))
return; // this is a relative link or anchor link
if(isExternalUrl(aHrefUrl))
alert('clicked external link');
});
<h3>Internal URLs:</h3>
<ul>
<li><a href="stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls" target="_blank">stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls</a></li>
<li><a href="www.stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls" target="_blank">www.stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls</a></li>
<li><a href="//stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls" target="_blank">//stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls</a></li>
<li><a href="//www.stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls" target="_blank">//www.stackoverflow.com/questions/6238351/fastest-way-to-detect-external-urls</a></li>
</ul>
<h3>External URLs:</h3>
<ul>
<li><a href="http://www.yahoo.com" target="_blank">http://www.yahoo.com</a></li>
<li><a href="yahoo.com" target="_blank">yahoo.com</a></li>
<li><a href="www.yahoo.com" target="_blank">www.yahoo.com</a></li>
<li><a href="//www.yahoo.com" target="_blank">//www.yahoo.com</a></li>
</ul>
私の目的のために、shshawの回答に少し変更を加えて、リンクが空でないか、または1文字だけ(「#」であると想定)かどうかを確認しました。元の回答メソッドは誤検知を返します。これは、FAアイコンを追加して、ユーザーが私のページを離れることをユーザーに示すためのものです。
// same thing here, no edit
function checkDomain(url) {
if ( url.indexOf('//') === 0 ) { url = location.protocol + url; }
return url.toLowerCase().replace(/([a-z])?:\/\//,'$1').split('/')[0];
};
function isExternal(url) {
// verify if link is empty or just 1 char + original answer
return (url.length > 1 && url.indexOf(':') > -1 || url.indexOf('//') > -1 ) && checkDomain(location.href) !== checkDomain(url);
};
// add some icon to external links (function is called in an init method)
function addExternalLinkIcon(){
$("a[href]").each(function(i,ob){
// we check it
if(isExternal($(ob).attr("href"))){
// then add some beauty if it's external
// (we assume Font Awesome CSS and font is loaded for my example, of course :-P)
$(ob).append(" <i class='fa fa-external-link'></i> ");
}
});
}
すべきではない
function is_external( url ) {
return url.match( /[a-zA-Z0-9]*:\/\/[^\s]*/g ) != null;
}
トリックをしますか?絶対(内部)URLでは機能しません。
主な問題は、URLを解析し、そのホスト名を取得する方法です。それは次の方法で行うことができます:
var _getHostname = function(url) {
var parser = document.createElement('a');
parser.href = url;
return parser.hostname;
}
var isExternal = (_getHostname(window.location.href) !== _getHostname('http://john.doe'));
または、 is-url-external モジュールを使用できます。
var isExternal = require('is-url-external');
isExternal('http://john.doe'); // true | false