使用 JavaScript 将相对路径转换为绝对路径
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14780350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert relative path to absolute using JavaScript
提问by Jasper
There's a function, which gives me urls like:
有一个函数,它给了我这样的网址:
./some.css
./extra/some.css
../../lib/slider/slider.css
It's always a relative path.
它始终是一条相对路径。
Let's think we know current path of the page, like http://site.com/stats/2012/, not sure how do I convert these relative paths to real ones?
假设我们知道页面的当前路径,例如http://site.com/stats/2012/,不知道如何将这些相对路径转换为真实路径?
We should get something like:
我们应该得到类似的东西:
./some.css => http://site.com/stats/2012/some.css
./extra/some.css => http://site.com/stats/2012/extra/some.css
../../lib/slider/slider.css => http://site.com/lib/slider/slider.css
No jQuery, only vanilla javascript.
没有 jQuery,只有 vanilla javascript。
采纳答案by Bergi
This should do it:
这应该这样做:
function absolute(base, relative) {
var stack = base.split("/"),
parts = relative.split("/");
stack.pop(); // remove current file name (or empty string)
// (omit if "base" is the current folder without trailing slash)
for (var i=0; i<parts.length; i++) {
if (parts[i] == ".")
continue;
if (parts[i] == "..")
stack.pop();
else
stack.push(parts[i]);
}
return stack.join("/");
}
回答by Elad
The most simple, efficient and correct way to do so it to just use URLapi.
最简单、有效和正确的方法就是使用URLapi。
new URL("http://www.stackoverflow.com?q=hello").href;
//=> http://www.stackoverflow.com/?q=hello"
new URL("mypath","http://www.stackoverflow.com").href;
//=> "http://www.stackoverflow.com/mypath"
new URL("../mypath","http://www.stackoverflow.com/search").href
//=> "http://www.stackoverflow.com/mypath"
new URL("../mypath", document.baseURI).href
//=> "https://stackoverflow.com/questions/mypath"
Performance wise, this solution is on par with using string manipulation and twice as fast as creating atag.
在性能方面,此解决方案与使用字符串操作相当,速度是创建a标签的两倍。
回答by allenhwkim
Javascript will do it for you. There's no need to create a function.
Javascript 会为你做这件事。无需创建函数。
var link = document.createElement("a");
link.href = "../../lib/slider/slider.css";
alert(link.protocol+"//"+link.host+link.pathname+link.search+link.hash);
// Output will be "http://www.yoursite.com/lib/slider/slider.css"
But if you need it as a function:
但是如果你需要它作为一个函数:
var absolutePath = function(href) {
var link = document.createElement("a");
link.href = href;
return (link.protocol+"//"+link.host+link.pathname+link.search+link.hash);
}
Update:Simpler version if you need the full absolute path:
更新:如果您需要完整的绝对路径,则使用更简单的版本:
var absolutePath = function(href) {
var link = document.createElement("a");
link.href = href;
return link.href;
}
回答by madmurphy
This from MDNis unbreakable!
这来自MDN是牢不可破的!
/*\
|*|
|*| :: translate relative paths to absolute paths ::
|*|
|*| https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|
|*| The following code is released under the GNU Public License, version 3 or later.
|*| http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
\*/
function relPathToAbs (sRelPath) {
var nUpLn, sDir = "", sPath = location.pathname.replace(/[^\/]*$/, sRelPath.replace(/(\/|^)(?:\.?\/+)+/g, ""));
for (var nEnd, nStart = 0; nEnd = sPath.indexOf("/../", nStart), nEnd > -1; nStart = nEnd + nUpLn) {
nUpLn = /^\/(?:\.\.\/)*/.exec(sPath.slice(nEnd))[0].length;
sDir = (sDir + sPath.substring(nStart, nEnd)).replace(new RegExp("(?:\\/+[^\\/]*){0," + ((nUpLn - 1) / 3) + "}$"), "/");
}
return sDir + sPath.substr(nStart);
}
Sample usage:
示例用法:
/* Let us be in /en-US/docs/Web/API/document.cookie */
alert(location.pathname);
// displays: /en-US/docs/Web/API/document.cookie
alert(relPathToAbs("./"));
// displays: /en-US/docs/Web/API/
alert(relPathToAbs("../Guide/API/DOM/Storage"));
// displays: /en-US/docs/Web/Guide/API/DOM/Storage
alert(relPathToAbs("../../Firefox"));
// displays: /en-US/docs/Firefox
alert(relPathToAbs("../Guide/././API/../../../Firefox"));
// displays: /en-US/docs/Firefox
回答by optimizitor
If you want to make a relative-to-absolute conversion for a link from a custom webpage in your browser (not for the page that runs your script), you can use a more enhanced version of the function suggested by @Bergi:
如果您想对来自浏览器中自定义网页的链接(而不是运行脚本的页面)进行相对到绝对转换,您可以使用@Bergi 建议的功能的更增强版本:
var resolveURL=function resolve(url, base){
if('string'!==typeof url || !url){
return null; // wrong or empty url
}
else if(url.match(/^[a-z]+\:\/\//i)){
return url; // url is absolute already
}
else if(url.match(/^\/\//)){
return 'http:'+url; // url is absolute already
}
else if(url.match(/^[a-z]+\:/i)){
return url; // data URI, mailto:, tel:, etc.
}
else if('string'!==typeof base){
var a=document.createElement('a');
a.href=url; // try to resolve url without base
if(!a.pathname){
return null; // url not valid
}
return 'http://'+url;
}
else{
base=resolve(base); // check base
if(base===null){
return null; // wrong base
}
}
var a=document.createElement('a');
a.href=base;
if(url[0]==='/'){
base=[]; // rooted path
}
else{
base=a.pathname.split('/'); // relative path
base.pop();
}
url=url.split('/');
for(var i=0; i<url.length; ++i){
if(url[i]==='.'){ // current directory
continue;
}
if(url[i]==='..'){ // parent directory
if('undefined'===typeof base.pop() || base.length===0){
return null; // wrong url accessing non-existing parent directories
}
}
else{ // child directory
base.push(url[i]);
}
}
return a.protocol+'//'+a.hostname+base.join('/');
}
It'll return nullif something is wrong.
null如果有什么问题,它会返回。
Usage:
用法:
resolveURL('./some.css', 'http://example.com/stats/2012/');
// returns http://example.com/stats/2012/some.css
resolveURL('extra/some.css', 'http://example.com/stats/2012/');
// returns http://example.com/stats/2012/extra/some.css
resolveURL('../../lib/slider/slider.css', 'http://example.com/stats/2012/');
// returns http://example.com/lib/slider/slider.css
resolveURL('/rootFolder/some.css', 'https://example.com/stats/2012/');
// returns https://example.com/rootFolder/some.css
resolveURL('localhost');
// returns http://localhost
resolveURL('../non_existing_file', 'example.com')
// returns null
回答by Sebastien Lorber
function canonicalize(url) {
var div = document.createElement('div');
div.innerHTML = "<a></a>";
div.firstChild.href = url; // Ensures that the href is properly escaped
div.innerHTML = div.innerHTML; // Run the current innerHTML back through the parser
return div.firstChild.href;
}
This works on IE6 too, unlike some other solutions (see Getting an absolute URL from a relative one. (IE6 issue))
这也适用于 IE6,与其他一些解决方案不同(请参阅从相对地址获取绝对 URL。(IE6 问题))
回答by Corey Alix
The href solution only works once the document is loaded (at least in IE11). This worked for me:
href 解决方案仅在加载文档后才有效(至少在 IE11 中)。这对我有用:
link = link || document.createElement("a");
link.href = document.baseURI + "/../" + href;
return link.href;
See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
请参阅https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
回答by Shai Petel
The proposed and accepted solution does not support server relative URLs and does not work on absolute URLs. If my relative is /sites/folder1 it won't work for example.
提议和接受的解决方案不支持服务器相对 URL,也不适用于绝对 URL。例如,如果我的亲戚是 /sites/folder1,它将不起作用。
Here is another function that supports full, server relative or relative URLs as well as ../ for one level up. It is not perfect but covers a lot of options. Use this when your base URL is not the current page URL, otherwise there are better alternatives.
这是另一个支持完整、服务器相对或相对 URL 以及 ../ 的功能。它并不完美,但涵盖了很多选择。当您的基本 URL 不是当前页面 URL 时使用此选项,否则有更好的替代方法。
function relativeToAbsolute(base, relative) {
//make sure base ends with /
if (base[base.length - 1] != '/')
base += '/';
//base: https://server/relative/subfolder/
//url: https://server
let url = base.substr(0, base.indexOf('/', base.indexOf('//') + 2));
//baseServerRelative: /relative/subfolder/
let baseServerRelative = base.substr(base.indexOf('/', base.indexOf('//') + 2));
if (relative.indexOf('/') === 0)//relative is server relative
url += relative;
else if (relative.indexOf("://") > 0)//relative is a full url, ignore base.
url = relative;
else {
while (relative.indexOf('../') === 0) {
//remove ../ from relative
relative = relative.substring(3);
//remove one part from baseServerRelative. /relative/subfolder/ -> /relative/
if (baseServerRelative !== '/') {
let lastPartIndex = baseServerRelative.lastIndexOf('/', baseServerRelative.length - 2);
baseServerRelative = baseServerRelative.substring(0, lastPartIndex + 1);
}
}
url += baseServerRelative + relative;//relative is a relative to base.
}
return url;
}
Hope this helps. It was really frustrating not to have this basic utility available in JavaScript.
希望这可以帮助。在 JavaScript 中没有这个基本实用程序真的很令人沮丧。
回答by whY
I found a very simple solution to do this while still supporting IE 10 (IE doesn't support the URL-API) by using the History API(IE 10 or higher). This solution works without any string manipulation.
通过使用历史 API(IE 10 或更高版本),我找到了一个非常简单的解决方案,同时仍然支持 IE 10(IE 不支持 URL-API )。此解决方案无需任何字符串操作即可工作。
function resolveUrl(relativePath) {
var originalUrl = document.location.href;
history.replaceState(history.state, '', relativePath);
var resolvedUrl = document.location.href;
history.replaceState(history.state, '', originalUrl);
return resolvedUrl;
}
history.replaceState()won't trigger browser navigation, but will still modify document.locationand supports relative aswell as absolute paths.
history.replaceState()不会触发浏览器导航,但仍会修改document.location和支持相对以及绝对路径。
The one drawback of this solution is that if you are already using the History-API and have set a custom state with a title, the current state's title is lost.
此解决方案的一个缺点是,如果您已经在使用 History-API 并设置了带有标题的自定义状态,则当前状态的标题将丢失。
回答by Mohamed hesham
This will work. but only when you open a page with it's file name. it will not work well when you open a link like this stackoverflow.com/page. it will work with stackoverflow.com/page/index.php
这将起作用。但仅当您打开带有文件名的页面时。当您打开这样的链接时,它将无法正常工作stackoverflow.com/page。它将与stackoverflow.com/page/index.php
function reltoabs(link){
let absLink = location.href.split("/");
let relLink = link;
let slashesNum = link.match(/[.]{2}\//g) ? link.match(/[.]{2}\//g).length : 0;
for(let i = 0; i < slashesNum + 1; i++){
relLink = relLink.replace("../", "");
absLink.pop();
}
absLink = absLink.join("/");
absLink += "/" + relLink;
return absLink;
}

