maicFir / lessonNote

JS学习笔记
33 stars 11 forks source link

盘点操作URL中常用的几个高效API #5

Open maicFir opened 2 years ago

maicFir commented 2 years ago

通常在实际项目中,无论操作数据、或是dom,我们需要熟悉一些浏览器API,或是js原生给我们扩展的API,我们熟悉了这些API,某种意义上来说,一些高效的API方法常常会解惑你项目中遇到的很多疑难杂症。

本文只作一些笔者项目中关于URL常用到的API,希望在你项目中能带来一点思考和帮助。

正文开始...

location 对象

控制台下,window.location获取浏览器地址 URL 相关信息

// window.location
/*
https://www.baidu.com/s?wd=Reflect.%20defineProperty&rsv_spt=1#123
*/
const { href, origin, host, port, protocol, pathname, hash, search } = window.location;
console.log(href); // 获取整个URL xxx
console.log(origin); // 协议+域名+端口  https://www.baidu.com
console.log(host); // 主机名+端口号(http或者https会省略端口号)  www.baidu.com
console.log(port); // '' http默认端口80 https默认端口443
console.log(protocol); // 协议 https:
console.log(pathname); // 除了域名的路由地址路径
console.log(hash); // 路径带#的参数
console.log(search); // 地址?后面所有参数

location.searchlocation.hashlocation.originlocation.href是通常项目中几个比较高频的获取当前地址的一些参数方法,不过注意只有location.origin这个是只读的,其他API都是可读可写

URL

js中创建一个地址,使用场景,举个栗子,我们用URL模拟当前页面的地址

const url = new URL('https://www.baidu.com/s?wd=Reflect.%20defineProperty&rsv_spt=1#123');
console.log(url.search); // ?wd=Reflect.%20defineProperty&rsv_spt=1
console.log(url.hash); // #123
console.log(url.origin); // https://www.baidu.com
console.log(url.href); // 'https://www.baidu.com/s?wd=Reflect.%20defineProperty&rsv_spt=1#123'

URL这个原生构造的地址中属性与location获取地址上的通用属性都基本一样。唯一的区别是,location多了replacereload方法,URL除了拥有location的通用属性,没有replacereload方法,但是他具备一个获取参数的一个searchParamsAPI

...
console.log(url.searchParams);
// { 'wd' => 'Reflect. defineProperty', 'rsv_spt' => '1' }

console.log(url.searchParams.toString());
// wd=Reflect.+defineProperty&rsv_spt=1

searchParams

快速获取URL中携带参数的方法,这个在URL构建的地址中非常方便。比如现在有一个需求,我需要将一个地址的参数转换成keyvalue的键值对。

以前我们的做法是这样的

function formateQueryUrl() {
  const { search } = window.location;
  // 以?分割,获取url上的真正的参数
  const [, searchStr] = search.split('?');
  // 以&分割前后参数
  const arr = searchStr.split('&');
  const ret = {};
  arr.forEach((v) => {
    const [key, val] = v.split('=');
    ret[key] = val;
  });
  return ret;
}

现在我们可以更高效的利用URLsearchParams

// 与上面formateQueryUrl方法等价
function eazyFormateQueryUrl() {
  const url = new URL(window.location);
  return Object.fromEntries(url.searchParams.entries());
}
// 如果当前浏览器地址 https://www.badu.com?a=1&b=2
// {a:1,b:2}

这个eazyFormateQueryUrl方法是不是很简单,两行代码就搞定了格式化url中的参数,并且将一串字符串参数轻松的转换成了对象

注意上面的方法我们使用了Object.fromEntriesurl.searchParams.entries(),其实url.searchParams的构造函数就是URLSearchParams,而URLSearchParams是一个具有可迭代器功能的 API,所以你可以for...of或者entries操作。

同时我们注意fromEntries,我们看下这个API,通常我们不常用,一般我们都是entries操作得多,但是实际上fromEntries就是还原对象的entries操作,这里我们就是利用了这一点。

举个栗子

const ret = { name: 'Maic', public: 'Web技术学苑' };
const arr = Object.entries(ret);
console.log(arr);
// [['name', 'Maic'], ['public', 'Web技术学苑']]

如果你想将arr还原成以前的对象,那么你肯定想到循环的做法,像下面这样

...
const target = {};
arr.forEach(item => {
  const [key, val] = item;
  target[key] = val;
});
console.log(target);
// {name: 'Maic', public: 'Web技术学苑'}

其实不用循环,原生 Object 提供了一个API,它可以将entries数据还原成以前的。那么我们可以简单实现

const ret = { name: 'Maic', public: 'Web技术学苑' };
const arr = Object.entries(ret);
/* const target = {};
arr.forEach(item => {
  const [key, val] = item;
  target[key] = val;
});
*/
// 与下面等价
const target = Object.fromEntries(arr);
// {name: 'Maic', public: 'Web技术学苑'}

正因为如此,我们利用了fromEntries的这点特性,巧妙的将原数据进行转对象了。

对于URL,我们还需要可以动态的添加路径,比如下面一个栗子

function locationByNamePath(path) {
  const { origin } = window.location;
  const url = new URL(path, origin);
  window.location.href = url.href;
}
locationByNamePath('/index.html');
// https://www.baidu.com/index.html
locationByNamePath('/about.html');
// https://www.baidu.com/about.html

URLSearchParams

这个API是一个原生的构造函数,可以获取地址?后面的参数信息

举个栗子

var urlSearch = new URLSearchParams(window.location.search);
console.log(`${urlSearch}`);
// 打开百度,在控制台随便输入关键字搜索,控制台复制该断代码,就可以看到

URLSearchParams传入字符串

const search = new URLSearchParams('a=1&b=2&c=3');
console.log(search.toString()); // a=1&b=2&c=3

等价于

const search = new URLSearchParams(window.location.search);
console.log(search.toString()); // a=1&b=2&c=3

URLSearchParams传入数组,将一个对象转换成url参数,通常在ajaxget 请求拼接参数时,可能很有用

const obj = { a: 1, b: 2, c: 3 };
const search2 = new URLSearchParams(Object.entries(obj));
console.log(search2.toString());
//a=1&b=2&c=3
$.ajax({
  url: `xxxx?${search2}`,
  methods: 'get'
});

当我们使用fetch原生api请求时,new URLSearchParams可以作为body参数

const params = {
  name: 'maic',
  password: '123456'
};
fetch('https://baidu.com', {
  methods: 'POST',
  body: new URLSearchParams(params)
});

我们知道URLSearchParams具有可迭代器属性的特征,因此它像MapSet一样具有增删查改的特性

get 获取参数值

const obj = { a: 1, b: 2, c: 3 };
const search2 = new URLSearchParams(Object.entries(obj));
console.log(search2.get('a')); // 1
console.log(search2.get('b')); // 2
console.log(search2.get('c')); // 3

append,添加某个参数

...
search2.append('d', 'hello')
// a=1&b=2&c=3&d=hello

delete 删除某个参数

...
search2.delete('a');
console.log(search2.toString());
//b=2&c=3

set 修改参数

const obj = { a: 1, b: 2, c: 3 };
const search2 = new URLSearchParams(Object.entries(obj));
search2.set('a', '666');
console.log(`${search2}`);
// a=666&b=2&c=3&d=hello

是否存在has 判断有没有key

...
console.log(search2.has('a')); // true

获取URLSearchParams所有的key或者value

new URLSearchParams({a:1,b:2,c:3}).keys(),new URLSearchParams({a:1,b:2,c:3}).values()

const obj = { a: 1, b: 2, c: 3 };
const search2 = new URLSearchParams(Object.entries(obj));
const keys = Array.from(search2.keys());
console.log(keys);
// ['a', 'b', 'c']
const values = Array.from(search2.values());
// ['1', '2', '3']

对于URLSearchParams可以传字符串,可以是对象或是数组,当我们获取URLSearchParams的 key,直接调用xxx.keys()或者是xxx.values(),不过这样取出的值是一个迭代器,还需要用Array.from中转一下。

还原URLSearchParams参数

...
Object.fromEntries(search2.entries());
// {a:1,b:2,c:3}

总结

  1. location常用获取hostnameoriginsearchhash

  2. URL创建 url,并且拥有searchParams获取 url 中的?后面的参数

  3. 利用URLSearchParams高效格式化url参数,两行代码实现了格式化?参数

  4. URLSearchParams这个API可以直接获取 url 参数,并提供增删查改[append、delete、get、set、has]方法