获取url上的查询参数(hash前面和后面的部分)

356 阅读2分钟

需求

如何全面准确地获取URL上的查询参数,包括hash前面和后面的部分。比如:

https://example.com/test?type=card#/about?name=tom

这里需要获取到type=card和name=tom这两个参数。

首先,location.search只能获取到问号后面的查询参数,也就是hash前面的部分。对于上面的URL,location.search会返回"?type=card"。而hash后面的部分,也就是#后面的内容,可以通过location.hash获取,但里面的查询参数location.search是拿不到的。

要同时获取hash前和hash后的查询参数,这时候就需要分别处理这两个部分的参数,然后将它们合并起来。

可以按照以下步骤实现:

  1. 解析location.search中的参数:这部分是标准的查询参数。
  2. 解析location.hash中的参数:需要从hash中提取路径后的查询参数。
  3. 合并两部分参数,处理同名键时,hash中的参数覆盖search中的参数。

实现

function getAllQueryParams() {
  const params = {};

  // 处理search部分的参数
  const searchParams = new URLSearchParams(window.location.search);
  for (const [key, value] of searchParams) {
    params[key] = value;
  }

  // 处理hash部分的参数
  const hash = window.location.hash.substring(1);
  const queryIndex = hash.indexOf('?');
  if (queryIndex !== -1) {
    const hashQuery = hash.substring(queryIndex + 1);
    const hashParams = new URLSearchParams(hashQuery);
    for (const [key, value] of hashParams) {
      params[key] = value; // hash参数覆盖search参数
    }
  }

  return params;
}

// 测试
const queryParams = getAllQueryParams();
console.log(queryParams.type); // 输出 "card"
console.log(queryParams.name); // 输出 "tom"

多个问号

搜了网上有些实现会根据?分割location.hash中的查询参数,但如果hash中的查询参数中有多个问号?就不对了,比如:

https://example.com/test?type=card#/about?name=tom?asd=123

以下两种结果哪种是正确的呢?

{
    "type": "card",
    "name": "tom?asd=123"
}
{
    "type": "card",
    "name": "tom"
}

我们先验证一下,假如多个问号出现在location.search中,比如:

https://example.com/?name=tom?asd=123

URLSearchParams处理的结果是什么呢?

new URLSearchParams(location.search).get('name')

'tom?asd=123'

所以,第一种结果才是正确的,不能通过问号?分割查询参数,而是读取location.hash中第一个问号?作为查询参数的开头,后面的问号?都是查询参数的值。