常见场景

传递 URL 参数是页面A与页面B通信时常用的方法。如:页面A是新闻列表页面,在点击某一条新闻的时候,需要带着新闻 ID 打开页面B新闻详情页面 pageB?id=${id},这样页面B就能根据解析 URL 上的 ID 获取具体的新闻详情了。

常见的格式化和解析方法

🔥🔥🔥 推荐一个好用的解析工具:Prettier URL

给出一段参数:

const query = {
    a: 'a',
    b: 1,
    c:[1,2,3,{ cc: 'my_cc'}],
    d: {
        name:'name',
        value: { num: 1}    
    },
    e: "https://www.baidu.com?a=1&b=1#tag"
}

使用现有的库

先抛出结论:推荐使用 qs

query-string

地址:https://www.npmjs.com/package/query-string

stringify
import queryString from 'query-string';
console.log(queryString.stringify(query));

结果(c=1&c=2&c=3):a=a&a%3F.b=a_b&b=1&c=1&c=2&c=3&c=%5Bobject%20Object%5D&d=%5Bobject%20Object%5D&e=https%3A%2F%2Fwww.baidu.com%3Fa%3D1%26b%3D1%23tag

使用 comma 格式 stringify
import queryString from 'query-string';
console.log(queryString.stringify(query),{arrayFormat: 'comma'});

结果(c=1,2,3):a=a&a%3F.b=a_b&b=1&c=1,2,3,%5Bobject%20Object%5D&d=%5Bobject%20Object%5D&e=https%3A%2F%2Fwww.baidu.com%3Fa%3D1%26b%3D1%23tag

parse

解析:

import queryString from 'query-string';
const str = queryString.stringify(query),{arrayFormat: 'comma'})
queryString.parse(`?${str}`)

返回:

{
  a: "a", 
  b: "1", 
  c:[ "1","2","3",[object Object]"], 
  d: "[object Object]", 
  e: "https://www.baidu.com?a=1&b=1#tag"
}
总结
  • 不需要手动去掉 location.search?
  • 数组处理支持 arrayFormat: 'bracket' | 'index' | 'comma'
  • 具备 encodeURIComponent(key)
  • 具备 encodeURIComponent(value)
  • 无法处理 value 为对象的情况( 被处理成 '[object Object]'),stringify + parse 后 这种值会丢失
  • 重复的 key 的解析 ?a=1&a=a { a: ["1","a"]}

querystring

image.png
已经被废弃了,不要再使用了,这里直接给出结论

  • 需要手动去掉 location.search?
  • 数组处理支持 arrayFormat: 'bracket' | 'index' | 'comma'
  • 具备 encodeURIComponent(key)
  • 具备 encodeURIComponent(value)
  • 无法处理 value 为对象的情况( 被处理成 '[object Object]'),stringify + parse 后 这种值会丢失
    • 重复的 key 的解析 ?a=1&a=a { a: ["1","a"]}

qs 【推荐】

github: https://github.com/ljharb/qs

stringify
import qs from 'qs';
console.log(qs.stringify(query));

结果:a=a&b=1&c%5B0%5D=1&c%5B1%5D=2&c%5B2%5D=3&c%5B3%5D%5Bcc%5D=my_cc&d%5Bname%5D=name&d%5Bvalue%5D%5Bnum%5D=1&e=https%3A%2F%2Fwww.baidu.com%3Fa%3D1%26b%3D1%23tag&a%3F.b=a_b

parse

解析:

import queryString from 'query-string';
const str = queryString.stringify(query),{arrayFormat: 'comma'})
queryString.parse(`?${str}`)

结果:

{
   a: "a"
   b: "1"
   c: ["1","2",{ cc: "my_cc"}]
  d: { name:"name", value:{} num: "1"}}
  e: "https://www.baidu.com?a=1&b=1#tag" 
}
总结
  • 需要手动去掉 location.search?
  • 数组处理支持 arrayFormat: 'indices' | 'bracket' | 'repeat' | 'comma'
  • 具备 encodeURIComponent(key)
  • 具备 encodeURIComponent(value)
  • 可以处理 value 为对象的情况
  • 重复的 key 的解析 ?a=1&a=a { a: ["1","a"]}

自己实现格式化和解析(仅限于 value 是基本类型)

抛出结论:

  • 需要手动去掉 location.search?
  • 具备 encodeURIComponent(key)
  • 具备 encodeURIComponent(value)
  • 无法处理 value 为对象的情况( 被处理成 '[object Object]')

方法一: split + reduce

格式化
const stringify  = (query) => {
    return Object.keys(query).reduce((pre,key) => {
        return pre + `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}&`
    },'').slice(0,-1)
}

调用:console.log(stringify(query))
返回 :a=a&b=1&c=1%2C2%2C3%2C%5Bobject%20Object%5D&d=%5Bobject%20Object%5D&e=https%3A%2F%2Fwww.baidu.com%3Fa%3D1%26b%3D1%23tag

解析
const parse = (queryStr) => {
    const str = queryStr.replace(/^\?/,'')
    return queryStr.split('&').reduce((pre,key) => {
        const [k,v] = key.split('=')
        pre[decodeURIComponent(k)] = decodeURIComponent(v)
        return pre
    },{})
}

调用上面 stringigyparse(str)
返回:

{ a: 'a',
  b: '1',
  c: '1,2,3,[object Object]',
  d: '[object Object]',
  e: 'https://www.baidu.com?a=1&b=1#tag'
 }

方法二 URL + URLSearchParams

URL: https://developer.mozilla.org/zh-CN/docs/Web/API/URL

URLSearchParams:https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchPar...

格式化
const url = new URL("https://example.com/?a=hello&b=world");

console.log(url.href);
// https://example.com/?a=hello&b=world

console.log(url.origin);
// https://example.com

const add_params = {
  c: "a",
  d: new String(2),
  e: false.toString(),
};

const new_params = new URLSearchParams([
  ...Array.from(url.searchParams.entries()), // [["a","hello"],["b","world"]]
  ...Object.entries(add_params), // [["c","a"],["d","2"],["e","false"]]
]).toString();
console.log(new_params);
// a=hello&b=world&c=a&d=2&e=false

const new_url = new URL(`${url.origin}${url.pathname}?${new_params}`);

console.log(new_url.href);
// https://example.com/?a=hello&b=world&c=a&d=2&e=false

// Here it is as a function that accepts (URL, Record<string, string>)
const addSearchParams = (url, params = {}) =>
  new URL(
    `${url.origin}${url.pathname}?${new URLSearchParams([
      ...Array.from(url.searchParams.entries()),
      ...Object.entries(params),
    ])}`,
  );

使用上面数据:

 const url = new URL("https://example.com/?a1=hello&b1=world");
  console.log("url==>", url);
  const addSearchParams = (url, params = {}) =>
    new URL(
      `${url.origin}${url.pathname}?${new URLSearchParams([
        ...Array.from(url.searchParams.entries()),
        ...Object.entries(params)
      ])}`
    );

  console.log("return url==>", addSearchParams(url, query).toString());
  

返回结果:`
https://example.com/?a1=hello&1b=world&a=a&b=1&c=1%2C2%2C3%2C... `

解析
const { searchParams } = new URL(url);
const result = {}
for(let [key, value] of searchParams){
      result[key] = value;
    }
    return result;
}

parse 之后:

{ a1: 'hello',
  '1b': 'world',
  a: 'a',
  b: '1',
  c: '1,2,3,[object Object]',
  d: '[object Object]',
  e: 'https://www.baidu.com?a=1&b=1#tag',
  'a?.b': 'a_b' }

总结

  • URLURLSearchParams 为我们实现 URL 参数格式化和解析提供了新的思路
  • 总体来看推荐使用 qs 这个库来实现,它的支持能力最强

specialcoder
2.2k 声望170 粉丝

前端 设计 摄影 文学