出处:掘金

原作者: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

这种方法存在几个问题:

  1. 易读性差:当 URL 变得复杂时,拼接和模板字符串会变得难以阅读和维护
  2. 容易出错:拼接过程中容易出错(例如漏掉斜杠)
  3. 缺乏类型安全:拼接字符串无法提供编译时的类型检查,容易引入错误

使用 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;
}

qs

www.npmjs.com/package/qs

query-string

https://www.npmjs.com/package/query-string