javascript 如何使用标准浏览器API计算相对URL

xyhw6mcr  于 2023-01-01  发布在  Java
关注(0)|答案(3)|浏览(140)

标准URL object可用于从相对URL和基本URL计算绝对URL,如下所示。

const base = 'http://example.com/'
const relative = '/foo/bar?quux=123'
const absolute = new URL(relative, base).href
console.assert(absolute === 'http://example.com/foo/bar?quux=123')

然而,我不知道如何使用URL对象来做相反的事情。

const base = 'http://example.com/'
const absolute = 'http://example.com/foo/bar?quux=123'
const relative = '???'
console.assert(relative === '/foo/bar?quux=123')

浏览器API是否提供了构建相对URL的标准化方法,还是我需要使用第三方解决方案?

aor9mmx1

aor9mmx11#

浏览器API是否提供了构造相对URL的标准化方法?
是的,他们有。你已经用过了,URL
或者,您可以创建一个临时的<a>-元素并从中获取值。新创建的<a>-元素或URL都实现了location,因此您可以提取location-属性:

// use <a href ...>
const absolute = `http://example.com/foo/bar?quux=123`;
const hrefTmp = document.createElement(`a`);
hrefTmp.href = absolute;
console.log(`Absolute from <a>: ${hrefTmp.href}`);
console.log(`Relative from <a>: ${hrefTmp.pathname}${hrefTmp.search}`);

// using URL
const url = new URL(absolute);
console.log(`Absolute from url: ${url.href}`);
console.log(`Relative from url: ${url.pathname}${url.search}`);

// using URL with a different base path
const baseOther = `http://somewhere.eu`;
const urlOther = new URL(`${url.pathname}${url.search}`, baseOther );
console.log(`Absolute from urlOther: ${urlOther.href}`);
console.log(`Relative from urlOther: ${urlOther.pathname}${urlOther.search}`);
.as-console-wrapper { top: 0; max-height: 100% !important; }
0tdrvxhp

0tdrvxhp2#

最后我做了以下几点。

const base = 'http://example.com/'
const absolute = 'http://example.com/foo/bar?quux=123'
const relative = ((temp) => {
  return absolute.startsWith(base) ? temp.pathname.concat(temp.search) : temp.href
})(new URL(absolute, base))
console.assert(relative === '/foo/bar?quux=123')
ssm49v7z

ssm49v7z3#

有一个名为relateurl的npm模块运行良好,但它对url(注意小写)的依赖在最新的Webpack和React中造成了轻微的问题。我发布了另一个名为relativize-url的模块,它使用URL(shouty-caps),到处都支持。它非常小,所以你可以安装它,或者只是从index.js中窃取代码。

const components = [
  {name: 'protocol', write: u => u.protocol },
  {name: 'hostname', write: u => '//' + u.hostname },
  {name: 'port', write: u => u.port === '' ? '' : (':' + u.port) },
  {name: 'pathname', write: (u, frm, relativize) => {
    if (!relativize) return u.pathname;
    const f = frm.pathname.split('/').slice(1);
    const t = u.pathname.split('/').slice(1);
    const maxDepth = Math.max(f.length, t.length);
    let start = 0;
    while(start < maxDepth && f[start] === t[start]) ++start;
    const rel = f.slice(start+1).map(c => '..')
          .concat(t.slice(start)).join('/');
    return rel.length <= u.pathname.length ? rel : u.pathname
  }},
  {name: 'search', write: u => u.search },
  {name: 'hash', write: u => u.hash},
];

function relativize (rel, base, opts = {}) { // opts not yet used
  const from = new URL(base);
  const to = new URL(rel, from);
  let ret = '';
  for (let component of components) {
    if (ret) { // force abs path if e.g. host was diffferent
      ret += component.write(to, from, false);
    } else if (from[component.name] !== to[component.name]) {
      ret = component.write(to, from, true);
    }
  }
  return ret;
}

pathname处理程序中有额外的代码,可以为您提供良好的最小相对路径。

const base = 'http://a.example/b/e/f?g=h#i'
const target = 'http://a.example/b/c/d?j=k#l'
console.log(relativize(target, base))
// got '../c/d'; let's check it:
console.log(new URL('../c/d', base).href === target)
// true
console.log(relativize('http://a.example/b?a=b','http://a.example/b?c=d'))
// ?a=b
console.log(relativize('http://a.example/b#asdf', 'http://a.example/b'))
// #asdf
console.log(relativize('http://a.example/b', 'http://c.example/d'))
// //a.example/b

请报告https://github.com/ericprud/relativize-url/issues中的错误。

相关问题