一天一工具 —— qs

2,851 阅读2分钟

今天介绍的工具库是 qs。它支持嵌套对象向 search-string 的序列化及反序列化。

背景

什么是 search-string? 简单来说地址栏 ? 及后面的参数就是 search-string。

var url = new URL('https://developer.mozilla.org/en-US/docs/Web/API/URL/search?q=123'); 
var queryString = url.search; // "?q=123"

一般来说 search-string 使用的是 URL encode,如果你使用过 URLSearchParams,它支持将简单的扁平化对象序列化成 search-string。

var paramsString = "q=URLUtils.searchParams&topic=api"
var searchParams = new URLSearchParams(paramsString);

for (let p of searchParams) {
  console.log(p);
}

searchParams.has("topic") === true; // true
searchParams.get("topic") === "api"; // true
searchParams.getAll("topic"); // ["api"]
searchParams.get("foo") === null; // true
searchParams.append("topic", "webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=api&topic=webdev"
searchParams.set("topic", "More webdev");
searchParams.toString(); // "q=URLUtils.searchParams&topic=More+webdev"
searchParams.delete("topic");
searchParams.toString(); // "q=URLUtils.searchParams"

上面是 MDN 的官方示例,可以看到 URLSearchParams 支持解析生成一个封装对象用于操作、查询 search-string。不过,可以看到这种操作方式十分繁琐,直观下我们更希望直接解析得到一个 Plain Object,使用 searchParams.foo 而不是 searchParams.get('foo')

使用 qs

今天我们的主角qs就很好地解决了这个问题。

import qs from "qs";

var paramsString = "q=URLUtils.searchParams&topic=api";

var query = qs.parse(paramsString);

console.log(query); // {q: "URLUtils.searchParams", topic: "api"}
console.log(qs.stringify(query)); // q=URLUtils.searchParams&topic=api

qs.parse 直接生成了一个 Plain Object,而 qs.stringify 也直接使用 Plain Object 转化成 query-string。

再一大亮点就是 qs 支持嵌套对象的解析。

import qs from "qs";

const obj = { a: "1", b: { c: "2" }, c: [1, 2, 3] };

console.log(new URLSearchParams(obj).toString());
// a=1&b=%5Bobject+Object%5D&c=1%2C2%2C3

const objString = qs.stringify(obj, { allowDots: true });

console.log(objString);
// a=1&b.c=2&c%5B0%5D=1&c%5B1%5D=2&c%5B2%5D=3
console.log(qs.parse(objString, { allowDots: true }));
// { a: "1", b: { c: "2" }, c: [1, 2, 3] }

可以看到 URLSearchParams 并不直接支持嵌套对象的序列化,产生了错误的结果,而 qs.stringify 正常生成了 query string,但是这里要注意使用了 allowDots 不转译 . 号,那么使用 qs.parse 的使用也需要加上 allowDots 来正常解析字符串。

场景

前端应用不断丰富、完善的今天,页面之间的跳转、衔接是必需的。在跳转路由的时候,我们就需要为即将进入的页面提供一些关键信息,比如某个实体的 id 、表格的查询条件、页码等。使用 search string 也就非常普遍。

根据使用的场景,建议只在跳转之后的第一次渲染获取 search string 的内容并解析出参数对象来初始化页面中的组件,在状态更新的时候使用 history.replace (react-router)更新路由中的 search 参数,通过设定页面中的关键参数,便于用户对链接进行分享时能够正常打开并还原页面状态。