学习前提

理解URL的路径、查询参数和片段,以及DOM事件。

本课完成后你能做什么

安全更新查询参数并保留其他状态,理解导航与History API各自的职责。

先理解机制

URL包含协议、主机、路径、查询与片段,不能靠字符串加?或&来可靠修改。用new URL处理结构,searchParams读取和替换参数。set替换同名值,append允许重复值;业务只允许一个语言参数时应使用set。

把已有URL复制后只改目标参数,可以保留文章id、搜索词和hash。中文和空格由序列化处理,不需要先encodeURIComponent再交给searchParams,否则可能二次编码。编码只是结构转义,不是授权或安全验证。

location.assign会导航并加载新页面;history.replaceState改变地址栏但不自动向服务器请求新内容,pushState增加历史记录也不会自动渲染。若页面语言由服务器决定,只改历史地址不会让正文翻译,必须导航或实现对应的客户端渲染。

从查询参数读入的值仍是不可信输入:语言使用允许列表,分页转换后限制范围,跳转目的地检查协议和源。不要让用户提供的next参数直接成为任意外站跳转。可分享状态应只包含必要信息,不把私密草稿写进URL。

可运行示例

运行方式:在独立练习网页的开发者工具Console中运行JavaScript;不要在含有重要表单的页面练习。修改输入后重新运行完整示例。

function languageURL(current, language) {
  if (!['zh', 'en'].includes(language)) throw new Error('Unsupported language');
  const url = new URL(current);
  if (language === 'en') url.searchParams.set('lang', 'en');
  else url.searchParams.delete('lang');
  return url.href;
}
const current = 'https://example.com/index.php?id=42&q=CSS%20Grid#practice';
console.log(languageURL(current, 'en'));
console.log(languageURL(languageURL(current, 'en'), 'zh'));
// In an actual language-link handler, navigate to the returned URL.
// location.assign(languageURL(location.href, 'en'));

推演与验证

英文目标应保留id42、搜索词和#practice,只新增lang=en。中文目标移除lang而其他值不变。序列化可能把空格写成+,这是等价编码,比较时用searchParams读值而不是依赖原始字符串格式。

常见错误与边界

此例用example.com作为纯函数输入,注释掉的导航代码不会执行。hash通常不发送给服务器,因此服务端生成语言链接时需由浏览器保留当前片段。

动手练习

给课程搜索增加page参数,新的关键词提交时重置到1,但切换语言时保留当前页。写出两个独立函数与反例。

参考解法与理由

每个函数复制URL并仅修改自己负责的字段。搜索函数设置q与page,语言函数仅处理lang。测试含中文、&和#的关键词,验证它们仍是参数值而不是破坏URL结构。

进一步阅读