Convert relative path to absolute using JavaScript

2020-01-27 00:57发布

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?

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.

11条回答
再贱就再见
2楼-- · 2020-01-27 01:40

The href solution only works once the document is loaded (at least in IE11). This worked for me:

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

查看更多
做个烂人
3楼-- · 2020-01-27 01:44

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:

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.

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
查看更多
三岁会撩人
4楼-- · 2020-01-27 01:51

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

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 a tag.

查看更多
该账号已被封号
5楼-- · 2020-01-27 01:51

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

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;
}
查看更多
来,给爷笑一个
6楼-- · 2020-01-27 01:57
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))

查看更多
登录 后发表回答