前端做跳转,最容易改出 bug 的就是 location 这几个方法混用。上周排查一个问题:用户点「退出」后还能按返回键回到后台首页,页面直接显示了缓存数据。原因不是权限没清,而是退出时用的是 location.assign。
location.assign 的基本行为
assign 是 window.location 对象的方法,作用是加载一个新地址,并且会在浏览历史里新增一条记录。
location.assign('https://example.com/list');
// 等价写法
location.href = 'https://example.com/list';它接受一个 URL 字符串。相对路径也可以,会基于当前页面的地址解析。传空字符串会刷新当前页,这一点常被忽略。
三个跳转方式的差别
- assign(url):新增历史记录,用户能点返回回到原页面。
- replace(url):替换当前记录,返回键会跳过原页面。
- href = url:和 assign 行为几乎一致,只是写法不同。
所以判断标准很简单:这个页面是否还值得被「返回」。登录页、支付中间页、退出登录页,都不应该留在历史里,要用 replace。
几个实际会遇到的情况
第一种,页面在 iframe 里。直接写 location.assign 改的是 iframe 自己的地址,想改顶层页面得用 window.top.location,跨域时会被浏览器拦截。
第二种,用户还没保存表单。直接 assign 会丢掉输入内容,正规做法是监听 beforeunload 给出提示。
第三种,在单页应用里。用 Vue Router 或 React Router 时手动改 location 会触发整页刷新,路由状态全丢,应该用 router.push。
assign 会抛错吗
会。页面已经卸载,或者在沙箱 iframe 里调用,浏览器会报 SecurityError。另外要小心拼接地址时混进 javascript: 开头的字符串,这是老牌的 XSS 入口,赋值前先校验协议是不是 http 或 https 更稳妥。
和 history.pushState 怎么选
pushState 只改地址栏和历史记录,不发起请求,页面内容由 JS 自己渲染,适合单页应用内部路由。assign 是真正发起一次导航,会重新加载资源。想做无刷新路由,别用 assign。
回头看那个退出登录的问题,改法就是退出时把 token 清掉,再用 replace 跳到登录页。这样返回键也回不到有数据的状态。