烟消火灭网

用 Vue 做单页应用,迟早会撞上一个问题:怎么跳到外部链接。`router.push` 不行,它只认内部路由。`` 倒是可以,但有时候你在 JS 逻辑里,比如提交表单成功后要跳转,或者点击某个按钮动

vue跳转到外部链接

用 Vue 做单页应用,外部迟早会撞上一个问题:怎么跳到外部链接。链接`router.push` 不行,外部它只认内部路由。链接`` 倒是外部可以,但有时候你在 JS 逻辑里,链接比如提交表单成功后要跳转,外部或者点击某个按钮动态拼 URL,链接这时候就得另想办法。外部

最直接的链接方式是 `window.location.href`。比如用户点击"去支付",外部你拿到后端返回的链接支付地址,直接赋值就行:

window.location.href = 'https://pay.example.com/order/123'

这行代码会把当前页面整个替换掉。外部浏览器历史里会多一条记录,链接用户点后退能回来。外部够用,但有个小坑——如果目标地址跟当前页面同源,Vue Router 可能拦截不到,页面直接刷新了。对 SPA 来说,刷新意味着状态全丢。所以用之前想清楚,你接不接受这次刷新。

不想刷新的话,`window.open` 是另一个选择。它开新标签页,原页面不动:

window.open('https://example.com', '_blank')

但浏览器对 `window.open` 有弹窗拦截。如果这行代码不在用户点击的同步回调里,比如放在 `setTimeout` 或者 `await` 之后,大概率被拦。我踩过这个坑:一个导出功能,请求接口拿下载链接再 `window.open`,Chrome 直接屏蔽。后来改成先 `window.open` 一个空窗口,拿到链接后再改 `location`,才绕过去。

const win = window.open('', '_blank') axios.get('/api/export').then(res => {  win.location.href = res.data.url })

再说 `` 标签。Vue 模板里写 `` 完全没问题,但如果你用了 Vue Router 的 history 模式,得注意别让它被路由接管。加个 `target="_blank"` 或者 `rel="noopener"` 就稳了。`rel="noopener"` 不是可有可无的,新页面能通过 `window.opener` 反向操作你的原页面,安全上是个隐患。

<a href="https://example.com" target="_blank" rel="noopener noreferrer"> 外部链接 </a>

还有一种场景:链接是动态的,来自接口数据。比如后台配了个活动 banner,点击跳转地址不确定。这时候别用 `v-html` 拼 ``,容易出 XSS。用事件委托或者给元素绑 `click`,在方法里判断协议头。只允许 `http` 和 `https`,其他一律拦掉。

methods: {  goExternal(url) {  if (/^https?:\/\//.test(url)) {  window.location.href = url } } }

Vue Router 本身也留了个口子。`router.push` 传外部地址会报错,但你可以用 `router.resolve` 先解析,判断是不是外部链接,再决定用哪种方式跳。不过实际项目里很少有人这么绕,直接判断字符串前缀更省事。

我自己的习惯是:能开新标签就开新标签,用户体验更顺,原页面状态保留。必须当前页跳转的,比如 OAuth 回调,才用 `window.location.href`。至于 ``,它天生只服务内部路由,外部链接别硬塞,塞了也是白塞。

最后提一嘴 SSR 场景。服务端渲染时 `window` 不存在,任何 `window.location` 或 `window.open` 都得包在 `process.client` 判断或者 `onMounted` 里。否则构建直接报错。Nuxt 项目里这个坑很常见,写的时候多留个心眼。

访客,请您发表评论:

© 2026. sitemap