Henry
不会做一手好菜的全栈前端不是好产品经理
50 人赞了该文章
无论在 Node.js 程序还是 HTML 前端程序里,我们都免不了像下面这样手工拼 URL 搜索字符串(URL Search String,或称 Query String):
// 备注:习惯上我们用 k 和 p 分别代表 keywords 和 pageIndex 的缩写:
function getQueryString(params) {
if (params) {
const {
keywords,
pageIndex = 1
} = params;
return `?k=${encodeURIComponent(keywords || '')}&p=${pageIndex}`;
}
throw new Error('"params" 参数不能为空。');
}
// 返回“?k=%E5%85%B3%E9%94%AE%E5%AD%97&p=1”
console.log(getQueryString({ keywords: '关键字', pageIndex: 1 }));
如果你逐行阅读上面的代码,不难发现这段程序并不是很严谨,而且虽然只有两个参数,但是却需要考虑参数为 null 或 undefined,此外还需通过 encodeURIComponent() 函数来处理 UTF-8 编码问题。
而将 JSON 对象转为 URL 字符串还并不是最大的难题,如何从 location.search 解析出参数才是更大的问题。例如,从 react-router v4 开始,不再支持对 URL 参数,你需要自己写代码从 location.search 中解析出你需要的参数。
那么你可能会想有没有横跨不同浏览器和 Node.js 的现成解决方案或者开源项目呢?答案一定是有的,而且还是一个标准这就是 URLSearchParams(浏览器端文档 | Node.js 文档)。
浏览器代码
// 如果需要支持较低版本的 PC 浏览器,需要额外安装和引用 polyfill:
// $ npm install --save url-search-params
// import URLSearchParams from 'url-search-params';
const urlSearchParams = new URLSearchParams();
Node.js 代码
const { URLSearchParams } = require('url');
const urlSearchParams = new URLSearchParams();
const params = new URLSearchParams();
params.set('k', '关键字'); // 设置参数
params.set('p', 1); // 支持 Boolean、Number 等丰富类型
console.log(params.toString()); // k=%E5%85%B3%E9%94%AE%E5%AD%97&p=1
const params = new URLSearchParams('k=%E5%85%B3%E9%94%AE%E5%AD%97&p=1');
console.log(params.get('k')); // 返回字符串“关键字”,支持自动 UTF-8 解码
console.log(params.get('p')); // 返回字符串“1”
console.log(params.get('xxx')); // 如果没有 xxx 这个键,则返回 null
console.log(params.has('xxx')); // 当然也可以通过 has() 方法查询是否存在指定的键
console.log(params.keys()); // 返回一个 ES6 Iterator,内含 ['k', 'p']
console.log(params.values()); // 返一个 ES6 Iterator,内含 ['关键字', '1']
console.log(params.entries()); // 与 Map.prototype.entries() 类似
怎么样是不是无论生成还是解析都非常简单?而更妙的是它还完美支持 URL 搜索参数列表!
相信不少同学都有过不知该如何在 HTTP GET 参数中传递数组的经历,我看到过不少人使用的这种方式:
http://example.com/search?brands=bmw,audi,mercedes
事实上,上面这种方式是不够标准的,并且需要处理原本字符串中就包含“,”的情况,而在业界广为推荐的范式是这样的:
http://example.com/search?brands=bmw&brands=audi&brands=mercedes
在 Node.js 中,以 express 为例,可以通过下面的方法获得上面 brands 参数的值:
app.get('/search', (req, res) => {
console.log(req.query.brands); // 直接返回一个数组 ['bmw', 'audi', 'mercedes']
...
});
那么我们应该如何通过 URLSearchParams 来生成及解析这种标准参数形式呢?使用 append() 和 getAll() 方法就行:
let params = new URLSearchParams();
// 通过 append() 方法添加所有的选项值
params.append('brands', 'bmw');
params.append('brands', 'audi');
params.append('brands', 'mercedes');
const searchString = params.toString();
// 解析也同样简单
params = new URLSearchParams(searchString);
console.log(params.getAll('brands')); // 返回一个数组 ['bmw', 'audi', 'mercedes']
URLSearchParams 无疑是前端做查询字符串拼接、特别是实现前端路由的好帮手。这里还要啰嗦一句,由于还在试验阶段,因此 Node.js、Chrome、Firefox 以及各种 Polyfill 类库的实现略有不同,例如:
const params = new URLSearchParams({
k: '关键字',
p: 1
});
console.log(params.toString());
在 Chrome 和 Node.js 上可以获得我们预期的结果,而在 FireFox 和 Polyfill 类库上则不支持 JSON 的构造函数,起初还差点害我出了一次生产事故,另外 UC 浏览器的实现也有不同(不支持“?”开头的字符串作为构造参数),因此大家在初期使用的时候要格外小心,不多说了,直接给出 URLSearchParams API 文档地址: