简体   繁体   English

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

[英]Convert relative path to absolute using JavaScript

There's a function, which gives me urls like:有一个 function,它给我的网址如下:

./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,只有香草 javascript。

The most simple, efficient and correct way to do so it to just use URL api.最简单、有效和正确的方法就是使用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.在性能方面,该解决方案看齐使用字符串操作和快两倍,创建a标签。

Javascript will do it for you. Javascript 将为您完成。 There's no need to create a function.无需创建函数。

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;
}

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

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

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

The href solution only works once the document is loaded (at least in IE11). href 解决方案仅在加载文档后才有效(至少在 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请参阅https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base

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 问题)

The proposed and accepted solution does not support server relative URLs and does not work on absolute URLs.提议和接受的解决方案不支持服务器相对 URL,也不适用于绝对 URL。 If my relative is /sites/folder1 it won't work for example.例如,如果我的亲戚是 /sites/folder1,它将不起作用。

Here is another function that supports full, server relative or relative URLs as well as ../ for one level up.这是另一个支持完整、服务器相对或相对 URL 以及 ../ 的功能。 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 时使用此选项,否则有更好的替代方法。

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

我知道这是一个非常古老的问题,但您可以使用: (new URL(relativePath, location)).href

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://stackoverflow.com/a/14780463
  // http://stackoverflow.com/a/25833886 - this doesn't work in cordova
  // http://stackoverflow.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("/");
}

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).通过使用历史 API (IE 10 或更高版本),我找到了一个非常简单的解决方案,同时仍然支持 IE 10(IE 不支持 URL-API)。 This solution works without any string manipulation.此解决方案无需任何字符串操作即可工作。

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.location and 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 并设置了带有标题的自定义状态,则当前状态的标题将丢失。

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 .当您打开像这样的链接stackoverflow.com/page时,它不会很好地工作。 it will work with stackoverflow.com/page/index.php它将与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;
}

Try:尝试:

 /** * Convert relative paths to absolute paths * @author HaNdTriX * @param {string} html - HTML string * @param {string} baseUrl - base url to prepend to relative paths * @param {string[]} [attributes] - attributes to convert * @returns {string} */ function absolutify( html, baseUrl, attributes = [ "href", "src", "srcset", "cite", "background", "action", "formaction", "icon", "manifest", "code", "codebase", ] ) { // Build the regex to match the attributes. const regExp = new RegExp( `(?<attribute>${attributes.join( "|" )})=(?<quote>['"])(?<path>.*?)\\k<quote>`, "gi" ); return html.replaceAll(regExp, (...args) => { // Get the matched groupes const { attribute, quote, path } = args[args.length - 1]; // srcset may have multiple paths `<url> <descriptor>, <url> <descriptor>` if (attribute.toLowerCase() === "srcset") { const srcSetParts = path.split(",").map((dirtyPart) => { const part = dirtyPart.trim(); const [path, size] = part.split(" "); return `${new URL(path.trim(), baseUrl).toString()} ${size || ""}`; }); return `${attribute}=${quote}${srcSetParts.join(", ")}${quote}`; } const absoluteURL = new URL(path, baseUrl).href; return `${attribute}=${quote}${absoluteURL}${quote}`; }); } console.log( absolutify("<img src='./fooo.png'>", "https://example.com") )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM