簡體   English   中英

使用 JavaScript 將相對路徑轉換為絕對路徑

[英]Convert relative path to absolute using JavaScript

有一個 function,它給我的網址如下:

./some.css
./extra/some.css
../../lib/slider/slider.css

它始終是相對路徑。

假設我們知道頁面的當前路徑,例如http://site.com/stats/2012/ ,不確定如何將這些相對路徑轉換為真實路徑?

我們應該得到類似的東西:

./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

沒有 jQuery,只有香草 javascript。

最簡單、有效和正確的方法就是使用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"

在性能方面,該解決方案看齊使用字符串操作和快兩倍,創建a標簽。

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"

但是如果你需要它作為一個函數:

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

更新:如果您需要完整的絕對路徑,則使用更簡單的版本:

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

這應該這樣做:

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

這來自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);
}

示例用法:

/* 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

如果您想對來自瀏覽器中自定義網頁的鏈接(而不是運行腳本的頁面)進行相對到絕對轉換,您可以使用@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('/');
}

如果出現問題,它將返回null

用法:

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

href 解決方案僅在加載文檔后才有效(至少在 IE11 中)。 這對我有用:

link = link || document.createElement("a");
link.href =  document.baseURI + "/../" + href;
return link.href;

請參閱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;
}

這也適用於 IE6,與其他一些解決方案不同(請參閱從相對地址獲取絕對 URL。(IE6 問題)

提議和接受的解決方案不支持服務器相對 URL,也不適用於絕對 URL。 例如,如果我的親戚是 /sites/folder1,它將不起作用。

這是另一個支持完整、服務器相對或相對 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;
}

希望這可以幫助。 在 JavaScript 中沒有這個基本實用程序真的很令人沮喪。

我知道這是一個非常古老的問題,但您可以使用: (new URL(relativePath, location)).href

我不得不為已接受的解決方案添加一個修復程序,因為我們可以在 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("/");
}

通過使用歷史 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()不會觸發瀏覽器導航,但仍會修改document.location並支持相對路徑和絕對路徑。

此解決方案的一個缺點是,如果您已經在使用 History-API 並設置了帶有標題的自定義狀態,則當前狀態的標題將丟失。

這將起作用。 但僅當您打開帶有文件名的頁面時。 當您打開像這樣的鏈接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;
}

嘗試:

 /** * 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