如何将绝对URL转换为相对URL

时间:2020-02-23 03:55:52

标签: javascript

如何将绝对网址转换为相对网址?

相对绝对转换很简单

const rel = "../images/doggy.jpg"
const base = "https://example.com/pages/page.html?foo=bar#baz";

function relToAbs(baseHref, relHref) {
  const url = new URL(rel, base);
  return `${url.origin}${url.pathname}`;
}

console.log(base, rel);

朝相反的方向似乎需要一堆代码。

这就是我尝试过的。

const pageURL1 = 'https://example.com/bar/baz.html?bla=blap#hash';
const pageURL2 = 'https://example.com/bar/?bla=blap#hash';
const absURL1 = 'https://example.com/bar/image/doggy.jpg';
const absURL2 = 'https://example.com/image/kitty.jpg';
const absURL3 = 'https://example.com/bar/birdy.jpg';

const tests = [
  { pageHref: pageURL1, absHref: absURL1, expected: 'image/doggy.jpg', },
  { pageHref: pageURL1, absHref: absURL2, expected: '../image/kitty.jpg', },
  { pageHref: pageURL1, absHref: absURL3, expected: 'birdy.jpg', },
  { pageHref: pageURL2, absHref: absURL1, expected: 'image/doggy.jpg', },
  { pageHref: pageURL2, absHref: absURL2, expected: '../image/kitty.jpg', },
  { pageHref: pageURL2, absHref: absURL3, expected: 'birdy.jpg', },
];

for (const {pageHref, absHref, expected} of tests) {
  const actual = absToRel(pageHref, absHref);
  console.log(absHref, actual, actual === expected ? 'pass' : 'FAIL');
}


function absToRel(pageHref, absHref) {
  const pagePaths = dirPaths(pageHref).slice(0, -1);
  const absPaths = dirPaths(absHref);
  if (pagePaths[0] !== absPaths[0]) {
    return absHref;  // not same domain
  }
  // remove same paths
  const firstDiffNdx = firstNonMatchingNdx(pagePaths, absPaths);
  pagePaths.splice(0, firstDiffNdx);
  absPaths.splice(0, firstDiffNdx);

  // for each path still on page add a ..
  return [
    ...(new Array(pagePaths.length).fill('..')),
    ...absPaths,
  ].join('/');
}

function firstNonMatchingNdx(a, b) {
  let ndx = 0;
  while (ndx < a.length && a[ndx] === b[ndx]) {
    ++ndx;
  }
  return ndx;
}

function dirPaths(href) {
  const url = new URL(href);
  return [url.origin, ...url.pathname.split('/')];
}

1 个答案:

答案 0 :(得分:0)

您可以使用内置的URL类来帮助解析URL。这样,您的代码就可以只关注单个路径元素,而忽略搜索参数,域,模式等...

这就是我想出的。

  1. 删除公用目录
  2. 为每个页面路径添加..我们需要从上向上到达最近的祖先目录
  3. 抓住这些文件位于同一目录的极端情况

我不保证这是完美的或万无一失的,但希望它能使您接近所寻找的东西。

function pathParts(path) {
  let parts = path.split('/');
  let start = 0;
  let end = parts.length;

  // Remove initial blank part from root /
  if( !parts[0] ) {
    start = 1;
  }

  // Remove trailing / part
  if( !parts[parts.length - 1] ) {
    end -= 1;
  }

  return parts.slice(start, end);
}

function absToRel(pageHref, absHref) {
  var pageUrl = new URL(pageHref);
  var absUrl = new URL(absHref);

  // If the urls have different schemas or domain, relative is not possible
  if( pageUrl.origin !== absUrl.origin ) {
    return absHref;
  }

  var pagePath = pathParts(pageUrl.pathname)
  var absPath = pathParts(absUrl.pathname)

  // Remove common root paths
  while( absPath.length && pagePath[0] === absPath[0] ) {
    absPath.shift();
    pagePath.shift();
  }

  // For each path segment left on pagePath, we'll need a relative ..
  pagePath.fill('..');

  let relPath = [
    ...pagePath,
    ...absPath
  ].join('/');

  // If the paths do not require traversal up, use current directory relative path
  if( relPath[0] !== '.' ) {
    relPath = './' + relPath;
  }

  return relPath;
}
相关问题