
js跳转代码怎么写?几种常见页面跳转方式示例
JavaScript 跳转页面,最常见的写法是给 location.href 赋值。但实际开发中,跳转不只是“换一个网址”:是否保留当前页面、是否需要后退、地址是否可信、参数如何编码,以及项目是否使用前端路由,都会影响应该选哪种方式。
本文从浏览器原生跳转讲起,依次说明链接跳转、替换历史记录、延迟跳转、返回上一页、携带 URL 参数和前端路由,并给出可以直接运行的代码。示例均可放在 HTML 页面中的 <script> 标签内运行;代码区使用 HTML 实体转义,复制时应将代码内容还原为正常字符。
一、最常见的 JavaScript 页面跳转
让浏览器打开指定 URL,通常使用 window.location.href:
window.location.href = 'https://example.com/products';
window.location 表示当前页面地址及其导航能力。给 href 赋值后,浏览器会导航到新地址,并像用户点击普通链接一样保留当前页面的历史记录。用户通常可以按浏览器的“后退”按钮回到原页面。
也可以使用下面的写法:
window.location.assign('https://example.com/products');
location.assign(url) 与给 location.href 赋值的用途基本相同,都是导航到新地址并产生一条新的会话历史记录。两种写法选一种即可,不需要同时调用。
例如,用户点按钮后跳转:
<button id="go">查看商品</button>
<script>
document.querySelector('#go').addEventListener('click', function () {
window.location.href = '/products';
});
</script>
当跳转目标是站内页面时,使用以斜杠开头的路径(如 /products)通常比写死完整域名更便于部署到不同环境。需要注意,路径的解析依赖当前站点的部署方式:根路径以 / 开头,相对路径则会相对于当前 URL 的目录解析。
二、href、assign 和 replace 有什么区别
以下三种写法都能触发导航,但历史记录行为不同:
// 写法一:保留当前页面的历史记录
window.location.href = '/next';
// 写法二:同样保留当前页面的历史记录
window.location.assign('/next');
// 写法三:用新地址替换当前历史记录
window.location.replace('/next');
location.replace(url) 会用新地址替换当前会话历史中的当前条目。因此,用户通常不能通过“后退”回到被替换的那一页。这里的“替换”指浏览器历史记录行为,不代表服务器上的旧页面被删除。
常见选择如下:
- 普通页面跳转:用
location.href或location.assign(),保留后退能力。 - 登录后跳转到目标页:通常使用普通跳转,让用户仍能返回登录前的页面;具体体验要结合登录流程设计。
- 不希望用户通过后退回到当前中间页:可以考虑
location.replace(),例如某些一次性过渡页。
不要把 replace() 当作安全控制手段。它只影响当前标签页的历史记录,不会阻止用户重新打开旧 URL,也不能代替身份验证、权限检查或服务端跳转校验。
三、页面跳转和普通链接:优先使用合适的 HTML
如果用户点击后只是打开另一个地址,普通链接通常比 JavaScript 更合适:
<a href="/help">查看帮助</a>
链接自带键盘操作、复制链接、在新标签页打开等浏览器能力,也更容易被辅助技术识别。若页面上的控件执行的是动作(例如提交、保存、触发逻辑),用按钮;若它的功能是导航到一个地址,用链接。不要仅为了跳转而把链接改成没有语义的 div。
需要在新标签页打开时,可以使用 target="_blank":
<a href="https://example.com/" target="_blank" rel="noopener noreferrer">
在新标签页打开
</a>
如果在 JavaScript 中调用 window.open(),也要考虑新窗口与原窗口之间的关系:
window.open('https://example.com/', '_blank', 'noopener,noreferrer');
现代浏览器通常会阻止与用户操作没有直接关联的弹窗。因此,window.open() 最好在用户点击事件处理函数中同步调用,不要先等待网络请求或定时器,再尝试打开新窗口。
document.querySelector('#open').addEventListener('click', function () {
window.open('https://example.com/', '_blank', 'noopener,noreferrer');
});
页面通过新窗口打开不受信任的外部网站时,加入 noopener 可以避免新页面通过 window.opener 操作原页面;noreferrer 还会阻止发送来源信息,并在支持的浏览器中具有切断 opener 关系的效果。是否需要隐藏来源,应根据站点的隐私和业务要求判断。
四、延迟几秒后跳转
使用 setTimeout() 可以在指定毫秒数后跳转,例如显示提示后进入目标页:
const timerId = window.setTimeout(function () {
window.location.href = '/welcome';
}, 3000);
// 如有需要,可以在跳转发生前取消
// window.clearTimeout(timerId);
这个示例等待约 3 秒后开始导航。计时器并不保证精确在某个时刻执行:浏览器后台标签页节流、页面主线程繁忙等因素都可能造成延迟。如果用户不应被强制跳转,应该提供明确提示或取消入口;跳转逻辑还要考虑组件销毁、页面切换时清理计时器,避免留下不必要的回调。
在页面加载后定时跳转也可以这样写:
window.addEventListener('DOMContentLoaded', function () {
window.setTimeout(function () {
window.location.assign('/notice');
}, 2000);
});
DOMContentLoaded 表示 HTML 文档已解析完成,并不表示所有图片、样式表等资源都已加载。多数定时跳转不需要等待全部资源;如果确实需要等完整页面载入,可以监听 load,但不应无故延迟用户可见的操作。
五、返回上一页与指定地址回退
返回上一条浏览历史记录可以使用:
window.history.back();
等价地,也可以使用:
window.history.go(-1);
需要特别注意:浏览器历史记录不一定存在上一页。用户可能直接打开当前页面,或者从书签、外部应用进入,此时调用 back() 可能没有可见效果。若业务要求始终回到某个明确页面,不应假设用户一定有前一条历史记录,可以根据可信的业务状态选择目标地址:
function goBackOrHome() {
if (window.history.length > 1) {
window.history.back();
} else {
window.location.href = '/';
}
}
history.length 只能提供当前标签页历史条目数量的参考,不能准确证明上一条记录就是本站页面,也不能保证 back() 最终落到某个特定地址。涉及登录、付款或数据操作时,不要依赖它做权限判断或流程安全控制。
如果产品要求返回到特定的站内页面,通常应明确导航到该页面:
window.location.href = '/account';
也可以根据应用保存的、经过校验的状态决定目标。不要不加校验地把 URL 参数中的 returnUrl 直接交给 location.href,相关风险见后文的开放重定向说明。
六、带参数跳转:使用 URL 和 URLSearchParams
把参数拼到字符串中时,容易遗漏问号、& 符号或编码。推荐用 URL 和 URLSearchParams 构造地址:
const target = new URL('/search', window.location.origin);
target.searchParams.set('q', '咖啡机');
target.searchParams.set('page', '2');
window.location.href = target.href;
这段代码会生成类似 /search?q=咖啡机&page=2 的地址。浏览器会按 URL 规则编码查询参数。使用 set() 时,如果同名参数原本存在,它会被替换;如果希望保留同名参数并新增一项,可以使用 append()。
需要从当前地址读取查询参数时,可以这样写:
const currentUrl = new URL(window.location.href);
const keyword = currentUrl.searchParams.get('q');
const pageText = currentUrl.searchParams.get('page');
console.log(keyword);
console.log(pageText);
查询参数从 URL 读入后仍然是外部输入,不能仅因它出现在本站 URL 中就视为可信。使用前要检查是否存在、是否符合预期格式,并根据业务需要限制长度和取值范围。参数也可能出现在浏览器历史、服务器日志、监控系统或引用来源信息中,因此不适合放密码、访问令牌、身份证号等敏感数据。HTTPS 可以保护传输链路,但不会让 URL 参数自动变成机密存储。
若目标地址是固定的站内路由,也可以从当前页面的来源创建 URL:
const target = new URL('/orders', window.location.href);
target.searchParams.set('status', 'pending');
window.location.assign(target.href);
URL 构造器对无效 URL 会抛出异常。如果目标值来自用户输入,可以在使用前做异常处理和地址校验,而不是假设它一定有效。
七、修改地址但不重新加载页面
如果只是希望更新同源页面的地址栏,例如单页应用记录筛选条件,可以使用 History API:
const nextUrl = new URL(window.location.href);
nextUrl.searchParams.set('tab', 'history');
window.history.pushState({ tab: 'history' }, '', nextUrl);
pushState() 会增加一条历史记录,并修改地址栏,但不会自动加载新页面,也不会自动请求服务器。浏览器同样不会因为调用它而自动触发应用的路由渲染逻辑,页面代码需要自行更新界面,并在需要时监听 popstate 处理用户前进、后退。
window.addEventListener('popstate', function () {
const url = new URL(window.location.href);
renderPage(url.pathname, url.searchParams);
});
使用 history.replaceState(state, '', url) 可以修改当前历史条目,而不新增一条。pushState() 和 replaceState() 的 URL 必须满足同源限制;通常只能使用当前源下的地址,不能借此把地址栏改成任意外站地址。传入的状态对象应当可结构化克隆,不能传入函数、DOM 节点等不可克隆内容。
如果调用 pushState() 后没有同步渲染页面,地址栏与实际展示内容就可能不一致。反过来,传统多页站点若只是想进入新文档,应直接使用 location,不要为了“看起来像单页应用”而用 History API 代替正常导航。
八、前端路由项目应该怎么跳转
使用 React Router、Vue Router 等前端路由的项目,站内页面跳转通常应该调用路由库提供的链接或导航 API,而不是直接给 window.location.href 赋值。直接修改 location 会触发整页加载,可能丢失内存中的状态,也绕过路由器的导航守卫和页面过渡逻辑。
例如,React Router 常见写法如下(需在已配置路由的应用中运行):
import { Link, useNavigate } from 'react-router-dom';
function AccountMenu() {
const navigate = useNavigate();
return (
<div>
<Link to="/account">账户页面</Link>
<button onClick={() => navigate('/orders')}>
查看订单
</button>
</div>
);
}
Vue Router 中通常使用 <RouterLink>,或在组件中调用路由实例:
<RouterLink to="/account">账户页面</RouterLink>
<script>
export default {
methods: {
openOrders() {
this.$router.push('/orders');
}
}
}
</script>
路由库会负责应用内部的导航、历史记录和视图切换;具体 API 会随框架与版本有所差别,使用前应核对项目所用版本的文档。跳转到外部网站、需要浏览器下载行为或必须重新加载文档时,仍应使用普通链接或浏览器原生导航。
九、跳转目标来自参数时的安全边界
常见风险之一是开放重定向:页面接受一个外部提供的目标地址,并直接跳转过去。例如:
// 不安全示例:不要直接信任查询参数
const params = new URLSearchParams(window.location.search);
const next = params.get('next');
if (next) {
window.location.href = next;
}
攻击者可能把 next 设置为钓鱼网站地址,再把这个看起来属于本站的链接发给用户。用户完成本站登录或操作后被带到伪造页面,容易误以为该页面仍受本站信任。客户端校验不能替代服务端对重定向目标的校验;涉及登录回跳等流程,服务端也应采用允许列表、站内路由标识或其他可靠的校验方式。
如果业务只需要跳转到本站的几个固定页面,优先把外部输入映射到有限的路由,而不是接受任意 URL:
const allowedTargets = new Map([
['account', '/account'],
['orders', '/orders'],
['help', '/help']
]);
const params = new URLSearchParams(window.location.search);
const key = params.get('next');
const destination = allowedTargets.get(key);
if (destination) {
window.location.assign(destination);
} else {
window.location.assign('/');
}
如果确实需要接受完整 URL,至少要明确允许的协议、主机和路径,并用正确的 URL 解析方式处理,而不是只用字符串包含判断。仅检查地址“包含本站域名”并不可靠,因为攻击者可以构造相似字符串或把域名放在 URL 的其他位置。任何规则都应根据实际业务在可信边界(通常包括服务端)落实。
十、容易写错的几种情况
1. 把查询参数直接拼进地址
下面的写法容易在参数含有 &、#、空格或非 ASCII 字符时产生错误:
// 容易出错
window.location.href = '/search?q=' + input.value;
用 URLSearchParams 编码参数更稳妥:
const url = new URL('/search', window.location.origin);
url.searchParams.set('q', input.value);
window.location.href = url.href;
2. 误以为 replace 是清除全部历史
location.replace() 只替换当前历史条目,不会清空整个标签页历史,也不能禁止用户通过其他路径重新访问页面。
3. 以为 back 一定能回到本站
history.back() 只尝试回到浏览器上一条历史记录。它不能判断上一页是否属于本站,也不能保证有上一页。对固定业务目标,应明确导航到经过校验的页面。
4. 用跳转代替权限控制
在前端检查登录状态后跳到登录页,只能改善用户体验,不能保护数据或接口。用户可以绕过页面代码直接请求接口;服务端仍然必须验证身份与权限。
5. 认为参数编码等同于安全过滤
URLSearchParams 负责按 URL 规则编码查询参数,并不负责验证业务合法性,也不负责防止开放重定向、跨站脚本或越权访问。输入验证、输出编码、权限校验和重定向允许列表是不同问题,应分别处理。
6. 在新窗口打开时忽略 opener 风险
对新窗口打开的外部内容,使用 rel="noopener noreferrer" 或在 window.open() 中设置相应特性,避免不必要的窗口间控制关系。还要预期浏览器可能阻止非用户手势触发的弹窗。
7. 在前端路由中随意整页刷新
站内 SPA 页面跳转优先使用路由器 API;直接赋值 location.href 会进行文档级导航。反过来,不能仅调用 pushState() 就认为路由视图已经更新。
十一、怎么选择:快速对照
| 需求 | 推荐方式 | 主要特点 |
|---|---|---|
| 跳到普通页面 | location.href 或 location.assign() | 发生文档导航,保留当前历史记录 |
| 跳转且不保留当前历史条目 | location.replace() | 替换当前条目,不等于清空历史 |
| 用户点击后打开新标签页 | <a target="_blank"> 或 window.open() | 注意弹窗限制与 opener 关系 |
| 几秒后自动导航 | setTimeout() 后调用 location | 计时不保证精确,提供合适的用户体验 |
| 返回上一条历史 | history.back() | 不保证存在上一页,也不保证返回本站 |
| 单页应用站内切换 | 使用路由库的链接或导航 API | 通常不触发整页加载 |
| 只更新地址栏与应用历史 | history.pushState() / replaceState() | 不会自动加载文档或更新视图 |
结语
多数普通页面跳转,用 window.location.href = url 就足够;要替换当前历史条目,用 location.replace();要返回上一页,用 history.back(),但不能假设上一页存在或属于本站。站内 SPA 导航则应使用项目的路由 API。
真正容易出问题的通常不是语法,而是边界:参数要正确编码和验证,跳转目标不能盲目信任,敏感信息不应放进 URL,前端跳转不能代替服务端权限控制。根据导航类型选对工具,再把这些边界处理好,页面跳转才既可靠又安全。




