使用JavaScript将相对路径转换为绝对路径

时间:2022-09-18 13:24:38

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。

9 个解决方案

#1


35  

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

#2


50  

Javascript will do it for you. No need to create a function. no need to set basename.

Javascript会为你做。无需创建功能。无需设置basename。

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"

If you need to have a function, just wrap this as a function with 3 lines of code.

如果你需要一个函数,只需将它包装为一个包含3行代码的函数。

var absolutePath = function(href) {
    var link = document.createElement("a");
    link.href = href;
    return (link.protocol+"//"+link.host+link.pathname+link.search+link.hash);
}

---- UPDATED ---
More simpler version only if you need the absolute path

----更新---只有在需要绝对路径时才能使用更简单的版本

var absolutePath = function(href) {
    var link = document.createElement("a");
    link.href = href;
    return link.href;
}

#3


27  

The most simple, efficient and correct way to do so it to just use URL api.

最简单,有效和正确的方法,只使用URL api。

new URL("http://www.*.com?q=hello").href; //http://www.*.com/?q=hello"
new URL("mypath","http://www.*.com").href; //"http://www.*.com/mypath"
new URL("../mypath","http://www.*.com/search").href //"http://www.*.com/mypath"
new URL("../mypath", window.location.href).href //"https://*.com/questions/mypath"

See JSPerf. This solution is on par with using string manipulation and twice as fast as creating a tag.

请参见JSPerf。此解决方案与使用字符串操作相同,速度是创建标记的两倍。

#4


5  

This from MDN is 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, "$1"));
  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

#5


4  

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 null if 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

#6


3  

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获取绝对URL。(IE6问题))

#7


2  

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 = window.location.href + "/../" + href;
return link.href;

#8


1  

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中使用这个基本实用程序真的很令人沮丧。

#9


0  

I had to add a fix to the accepted solution because we can have slashes after # in our angularjs navigation.

我必须在已接受的解决方案中添加一个修复程序,因为我们可以在angularjs导航中的#之后添加斜杠。

function getAbsoluteUrl(base, relative) {
  // remove everything after #
  var hashPosition = base.indexOf('#');
  if (hashPosition > 0){
    base = base.slice(0, hashPosition);
  }

  // the rest of the function is taken from http://*.com/a/14780463
  // http://*.com/a/25833886 - this doesn't work in cordova
  // http://*.com/a/14781678 - this doesn't work in cordova
  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("/");
}

#1


35  

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

#2


50  

Javascript will do it for you. No need to create a function. no need to set basename.

Javascript会为你做。无需创建功能。无需设置basename。

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"

If you need to have a function, just wrap this as a function with 3 lines of code.

如果你需要一个函数,只需将它包装为一个包含3行代码的函数。

var absolutePath = function(href) {
    var link = document.createElement("a");
    link.href = href;
    return (link.protocol+"//"+link.host+link.pathname+link.search+link.hash);
}

---- UPDATED ---
More simpler version only if you need the absolute path

----更新---只有在需要绝对路径时才能使用更简单的版本

var absolutePath = function(href) {
    var link = document.createElement("a");
    link.href = href;
    return link.href;
}

#3


27  

The most simple, efficient and correct way to do so it to just use URL api.

最简单,有效和正确的方法,只使用URL api。

new URL("http://www.*.com?q=hello").href; //http://www.*.com/?q=hello"
new URL("mypath","http://www.*.com").href; //"http://www.*.com/mypath"
new URL("../mypath","http://www.*.com/search").href //"http://www.*.com/mypath"
new URL("../mypath", window.location.href).href //"https://*.com/questions/mypath"

See JSPerf. This solution is on par with using string manipulation and twice as fast as creating a tag.

请参见JSPerf。此解决方案与使用字符串操作相同,速度是创建标记的两倍。

#4


5  

This from MDN is 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, "$1"));
  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

#5


4  

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 null if 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

#6


3  

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获取绝对URL。(IE6问题))

#7


2  

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 = window.location.href + "/../" + href;
return link.href;

#8


1  

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中使用这个基本实用程序真的很令人沮丧。

#9


0  

I had to add a fix to the accepted solution because we can have slashes after # in our angularjs navigation.

我必须在已接受的解决方案中添加一个修复程序,因为我们可以在angularjs导航中的#之后添加斜杠。

function getAbsoluteUrl(base, relative) {
  // remove everything after #
  var hashPosition = base.indexOf('#');
  if (hashPosition > 0){
    base = base.slice(0, hashPosition);
  }

  // the rest of the function is taken from http://*.com/a/14780463
  // http://*.com/a/25833886 - this doesn't work in cordova
  // http://*.com/a/14781678 - this doesn't work in cordova
  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("/");
}