URL 参数处理 #

什么是 URL 参数? #

URL 参数(也称为查询字符串 Query String)是 URL 中 ? 后面的部分,用于向服务器传递数据。

text
https://example.com/search?q=javascript&page=1&size=10
                   │                      │
                   └─── 查询字符串开始 ────┘

结构:?key1=value1&key2=value2&key3=value3

URL 结构解析 #

text
┌─────────────────────────────────────────────────────────────┐
│                        URL 结构                              │
├─────────────────────────────────────────────────────────────┤
│  https://example.com:8080/path/page?id=123&name=John#top   │
│  └──┬──┘└────┬────┘└─┬┘└───┬───┘└───────┬───────┘└─┬─┘    │
│   协议    域名    端口  路径      查询参数     锚点        │
└─────────────────────────────────────────────────────────────┘

基础函数 #

getQueryString(name) #

获取 URL 中指定参数的值。

javascript
export const getQueryString = (name) => {
    const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
    const r = window.location.search.slice(1).match(reg);
    if (r != null) {
        return decodeURIComponent(r[2]);
    }
    return '';
};

使用示例 #

javascript
import { getQueryString } from './utils';

const url = 'https://example.com?id=123&name=John%20Doe&category=js';
window.location.search = '?id=123&name=John%20Doe&category=js';

const id = getQueryString('id');
const name = getQueryString('name');
const category = getQueryString('category');
const notExist = getQueryString('notExist');

console.log(id);
console.log(name);
console.log(category);
console.log(notExist);

实现原理 #

text
正则表达式解析:
┌─────────────────────────────────────────────────────────────┐
│  正则:(^|&)name=([^&]*)(&|$)                                │
├─────────────────────────────────────────────────────────────┤
│  (^|&)     匹配参数名前的位置(开头或 & 之后)                 │
│  name=     匹配参数名和等号                                   │
│  ([^&]*)   捕获参数值(非 & 的任意字符)                       │
│  (&|$)     匹配参数值后的位置(& 或结尾)                      │
└─────────────────────────────────────────────────────────────┘

匹配过程:
?id=123&name=John
    └──┘ 匹配 id=123
           └────┘ 匹配 name=John

getQueryParam(url) #

获取 URL 中所有参数,返回对象。

javascript
export const getQueryParam = (url) => {
    const queryString = (url ? url.split('?')[1] : window.location.search.slice(1)) || '';
    const queryParam = queryString.split('&').reduce((acc, item) => {
        const [key, value] = item.split('=');
        if (key !== '') {
            acc[key] = decodeURIComponent(value);
        }
        return acc;
    }, {});
    return queryParam;
};

使用示例 #

javascript
import { getQueryParam } from './utils';

const url = 'https://example.com/search?q=javascript&page=1&size=10';
const params = getQueryParam(url);

console.log(params);

const currentParams = getQueryParam();
console.log(currentParams);

处理边界情况 #

javascript
import { getQueryParam } from './utils';

console.log(getQueryParam('https://example.com'));
console.log(getQueryParam('https://example.com?'));
console.log(getQueryParam('https://example.com?key'));
console.log(getQueryParam('https://example.com?key='));

addQueryParam(url, param) #

向 URL 添加或更新参数。

javascript
export const addQueryParam = (url, param) => {
    const [baseUrl] = url.split('?');
    const queryParam = getQueryParam(url);
    const newQueryParam = { ...queryParam, ...param };
    const newQueryString = Object.entries(newQueryParam)
        .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
        .join('&');
    return `${baseUrl}?${newQueryString}`;
};

使用示例 #

javascript
import { addQueryParam } from './utils';

const url1 = 'https://example.com/search?q=js';
const newUrl1 = addQueryParam(url1, { page: 1, size: 10 });
console.log(newUrl1);

const url2 = 'https://example.com/search?q=js&page=1';
const newUrl2 = addQueryParam(url2, { page: 2, sort: 'date' });
console.log(newUrl2);

const url3 = 'https://example.com';
const newUrl3 = addQueryParam(url3, { id: 123, name: 'John' });
console.log(newUrl3);

进阶用法 #

构建查询字符串 #

javascript
const buildQueryString = (params) => {
    return Object.entries(params)
        .filter(([_, value]) => value !== undefined && value !== null)
        .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
        .join('&');
};

buildQueryString({ name: 'John', age: 25, city: '北京' });

解析完整 URL #

javascript
const parseUrl = (url) => {
    const parser = document.createElement('a');
    parser.href = url;
    return {
        protocol: parser.protocol,
        host: parser.host,
        hostname: parser.hostname,
        port: parser.port,
        pathname: parser.pathname,
        search: parser.search,
        hash: parser.hash,
        params: getQueryParam(url)
    };
};

parseUrl('https://example.com:8080/path/page?id=123#top');

URL 编码解码 #

javascript
const original = 'name=张三&city=北京';

const encoded = encodeURIComponent(original);
console.log(encoded);

const decoded = decodeURIComponent(encoded);
console.log(decoded);

编码对比 #

方法 编码范围 适用场景
encodeURIComponent A-Z a-z 0-9 - _ . ! ~ * ' ( ) 外的所有字符 参数值编码
encodeURI A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # 外的字符 完整 URL 编码
escape(已废弃) A-Z a-z 0-9 @ * _ + - . / 外的字符 不推荐使用
javascript
const url = 'https://example.com/search?q=你好世界';

console.log(encodeURI(url));
console.log(encodeURIComponent('你好世界'));

实际应用场景 #

1. 分页导航 #

javascript
import { getQueryString, addQueryParam } from './utils';

class Pagination {
    constructor() {
        this.currentPage = parseInt(getQueryString('page')) || 1;
        this.pageSize = parseInt(getQueryString('size')) || 10;
    }
    
    goToPage(page) {
        const newUrl = addQueryParam(window.location.href, { page });
        window.location.href = newUrl;
    }
    
    changeSize(size) {
        const newUrl = addQueryParam(window.location.href, { size, page: 1 });
        window.location.href = newUrl;
    }
    
    getOffset() {
        return (this.currentPage - 1) * this.pageSize;
    }
}

const pagination = new Pagination();
pagination.goToPage(2);

2. 搜索功能 #

javascript
import { getQueryString, addQueryParam, getQueryParam } from './utils';

class Search {
    constructor() {
        this.params = getQueryParam();
    }
    
    search(keyword) {
        const newUrl = addQueryParam(window.location.href, {
            q: keyword,
            page: 1
        });
        window.location.href = newUrl;
    }
    
    filter(filters) {
        const newUrl = addQueryParam(window.location.href, {
            ...filters,
            page: 1
        });
        window.location.href = newUrl;
    }
    
    getSearchParams() {
        return {
            keyword: getQueryString('q') || '',
            category: getQueryString('category') || 'all',
            sort: getQueryString('sort') || 'relevance'
        };
    }
}

3. 表单状态持久化 #

javascript
import { getQueryParam, addQueryParam } from './utils';

class FormState {
    constructor(formId) {
        this.form = document.getElementById(formId);
        this.loadState();
    }
    
    loadState() {
        const params = getQueryParam();
        Object.entries(params).forEach(([key, value]) => {
            const input = this.form.querySelector(`[name="${key}"]`);
            if (input) {
                input.value = value;
            }
        });
    }
    
    saveState() {
        const formData = new FormData(this.form);
        const params = {};
        formData.forEach((value, key) => {
            if (value) params[key] = value;
        });
        
        const newUrl = addQueryParam(
            window.location.pathname,
            params
        );
        window.history.replaceState({}, '', newUrl);
    }
}

const form = new FormState('searchForm');

4. 分享链接生成 #

javascript
import { addQueryParam } from './utils';

const generateShareLink = (baseUrl, data) => {
    return addQueryParam(baseUrl, {
        ref: 'share',
        uid: data.userId,
        ts: Date.now()
    });
};

const shareLink = generateShareLink('https://example.com/article/123', {
    userId: 'user_001'
});
console.log(shareLink);

性能优化 #

缓存解析结果 #

javascript
const queryParamsCache = new Map();

export const getQueryParamCached = (url) => {
    const cacheKey = url || window.location.href;
    
    if (queryParamsCache.has(cacheKey)) {
        return queryParamsCache.get(cacheKey);
    }
    
    const params = getQueryParam(url);
    queryParamsCache.set(cacheKey, params);
    
    return params;
};

批量参数处理 #

javascript
export const getMultipleQueryStrings = (names) => {
    const params = getQueryParam();
    return names.reduce((result, name) => {
        result[name] = params[name] || '';
        return result;
    }, {});
};

const { id, name, page } = getMultipleQueryStrings(['id', 'name', 'page']);
console.log(id, name, page);

常见问题 #

1. 中文乱码问题 #

javascript
import { getQueryString } from './utils';

const url = 'https://example.com?name=%E5%BC%A0%E4%B8%89';
window.location.search = '?name=%E5%BC%A0%E4%B8%89';

const name = getQueryString('name');
console.log(name);

2. 数组参数处理 #

javascript
const getArrayParam = (name) => {
    const params = getQueryParam();
    const value = params[name];
    if (!value) return [];
    return Array.isArray(value) ? value : [value];
};

const parseArrayParams = (url) => {
    const queryString = url.split('?')[1] || '';
    const params = {};
    
    queryString.split('&').forEach(item => {
        const [key, value] = item.split('=');
        if (key.endsWith('[]')) {
            const realKey = key.slice(0, -2);
            if (!params[realKey]) params[realKey] = [];
            params[realKey].push(decodeURIComponent(value));
        } else {
            params[key] = decodeURIComponent(value);
        }
    });
    
    return params;
};

3. 特殊字符处理 #

javascript
const safeGetQueryString = (name) => {
    try {
        return getQueryString(name);
    } catch (e) {
        console.error('URL 参数解析错误:', e);
        return '';
    }
};

下一步 #

现在你已经掌握了 URL 参数处理,接下来学习 Cookie 操作,了解客户端存储的另一种方式!

最后更新:2026-04-04