js跳转代码怎么写?几种常见页面跳转方式示例

运营资讯3小时前发布 jdkjadmin
0 00
js跳转代码怎么写?几种常见页面跳转方式示例

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,前端跳转不能代替服务端权限控制。根据导航类型选对工具,再把这些边界处理好,页面跳转才既可靠又安全。

© 版权声明

相关文章