出处:掘金
原作者:pe7er
在前端开发中,经常需要处理 URL,例如:
- 在发起 HTTP 请求时构建 API 端点
- 在页面导航时构建动态链接、拼接动态参数
传统上,常使用字符串拼接或模板语法来构建 URL。例如:
const baseUrl = "https://api.example.com";
const userId = 12345;
const endpoint = baseUrl + "/users/" + userId + "/details";
console.log(endpoint); // https://api.example.com/users/12345/details
import { TYPE_EDIT } from '@/constants/type.ts'
const type = TYPE_EDIT
const url = 'https://api.example.com/userInfo'
const newUrl = url + `?type=${type}&model=1&share=1&fromModule=wechat`
console.log(urlUrl) // https://api.example.com/userInfo?type=TYPE_EDIT&model=1&share=1&fromModule=wechat
这种方法存在几个问题:
- 易读性差:当 URL 变得复杂时,拼接和模板字符串会变得难以阅读和维护
- 容易出错:拼接过程中容易出错(例如漏掉斜杠)
- 缺乏类型安全:拼接字符串无法提供编译时的类型检查,容易引入错误
使用 URL 构造器
为了解决这些问题,现代 JavaScript 引入了 URL 构造器,可以更优雅和安全地处理 URL,其提供了一种更结构化和直观的方法来构建和操作 URL
基本用法
const baseUrl = "https://api.example.com";
const userId = 12345;
const url = new URL(`/users/${userId}/details`, baseUrl);
console.log(url.href); // https://api.example.com/users/12345/details
添加查询参数
const baseUrl = "https://api.example.com";
const userId = 12345;
const url = new URL(`/users/${userId}/details`, baseUrl);
url.searchParams.append('type', 'EDIT');
url.searchParams.append('module', 'wechat');
console.log(url.href); // https://api.example.com/users/12345/details?type=EDIT&module=wechat
查询参数为数组
逗号拼接:
// 拼接数组参数到 URL
const baseUrl = 'https://example.com';
const url = new URL(baseUrl);
const arrayParam = ['value1', 'value2', 'value3'];
url.searchParams.set('array', arrayParam.join(','));
console.log(url.toString()); // https://example.com/?array=value1,value2,value3
// 解析数组参数从 URL
const urlString = url.toString();
const parsedUrl = new URL(urlString);
const arrayParamString = parsedUrl.searchParams.get('array');
const parsedArrayParam = arrayParamString ? arrayParamString.split(',') : [];
console.log(parsedArrayParam); // ['value1', 'value2', 'value3']
多个同名参数:
// 拼接多个同名参数到 URL
const url = new URL(baseUrl);
const arrayParam = ['value1', 'value2', 'value3'];
arrayParam.forEach(value => url.searchParams.append('array', value));
console.log(url.toString()); // https://example.com/?array=value1&array=value2&array=value3
// 解析多个同名参数从 URL
const urlString = url.toString();
const parsedUrl = new URL(urlString);
const parsedArrayParam = parsedUrl.searchParams.getAll('array');
console.log(parsedArrayParam); // ['value1', 'value2', 'value3']
使用正则
/**
* 合并查询参数到 URL 的函数
* 将给定的查询对象 Query 合并到指定的 URL 中
*
* @param {Object} query - 要合并到 URL 中的查询对象
* @param {string} url - 作为基础的 URL,默认为当前页面的 URL
* @returns {string} 生成的合并查询参数后的新 URL
*/
export function getUrlMergeQuery(query = {}, url) {
url = url || window.location.href
const _orgQuery = getQueryObject(url)
const _query = {..._orgQuery,...query }
let _arr = []
for (let key in _query) {
const value = _query[key]
if (value) _arr.push(`${key}=${encodeURIComponent(_query[key])}`)
}
return `${url.split('?')[0]}${_arr.length > 0? `?${_arr.join('&')}` : ''}`
}
/**
* 从 URL 中提取查询参数对象
*
* @param {string} [url=window.location.href] - 要解析的 URL 字符串。如果未提供,则使用当前页面的 URL
* @returns {Object} - 包含提取的查询参数的对象
*/
export function getQueryObject(url = window.location.href) {
const search = url.substring(url.lastIndexOf('?') + 1);
const obj = {};
const reg = /([^?&=]+)=([^?&=]*)/g;
search.replace(reg, (rs, $1, $2) => {
const name = decodeURIComponent($1);
let val = decodeURIComponent($2);
val = String(val);
obj[name] = val;
return rs;
});
return obj;
}