常見場景
傳遞 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
已經被廢棄了,不要再使用了,這裏直接給出結論
- 需要手動去掉
location.search的? - 數組處理支持
arrayFormat:'bracket' | 'index' | 'comma' - 具備
encodeURIComponent(key) - 具備
encodeURIComponent(value) - 無法處理 value 為對象的情況( 被處理成
'[object Object]'),stringify + parse後 這種值會丟失 -
- 重複的 key 的解析 ?a=1&a=a
{ a: ["1","a"]}
- 重複的 key 的解析 ?a=1&a=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
},{})
}
調用上面 stringigy :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'
}
方法二 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' }
總結
URL和URLSearchParams為我們實現 URL 參數格式化和解析提供了新的思路- 總體來看推薦使用
qs這個庫來實現,它的支持能力最強