首页 / Nuxt 4 入门教程 / 导航:NuxtLink 与编程式导航

Nuxt 4 入门教程

导航:NuxtLink 与编程式导航

本教程共 50 篇 · 第 20 篇 · 更新于 2026-08-08 · 约 5 分钟阅读

NuxtNuxt4NuxtLink导航navigateTo

本节目标:会用 NuxtLink 做页面间跳转,理解它的预加载优化,并掌握编程式导航与 active 高亮。

20-1

页面之间跳转,Nuxt 提供了 <NuxtLink> 组件。它和原生 <a href="..."> 很像,但更聪明:点击时不会整页刷新,而是在 JavaScript 里更新网址并切换页面,配合第 21 章的过渡还能做动画。

<template>
  <header>
    <nav>
      <ul>
        <li><NuxtLink to="/about">关于</NuxtLink></li>
        <li><NuxtLink to="/posts/1">文章 1</NuxtLink></li>
        <li><NuxtLink to="/posts/2">文章 2</NuxtLink></li>
      </ul>
    </nav>
  </header>
</template>

to 属性写目标路径,用法和普通 <a>href 基本一致。NuxtLink 是 Nuxt 自带的,不用 import。

Note

<NuxtLink> 底层就是 Vue Router 的 <RouterLink>。Nuxt 在它外面多包了一层优化,所以能用 to,也能用 RouterLink 支持的其它属性。

20-2

<NuxtLink> 有个贴心能力:当链接进入浏览器视口(或你觉得快要点到它时),Nuxt 会提前把目标页面的组件和预取数据拉到本地。等你真点下去,页面几乎瞬间切换,因为东西早就准备好了。

这行为默认开启,不需要你配置。你要做的只是用 <NuxtLink> 而不是手写的 <a> 标签——后者不会触发预加载,点了还是得等网络。

20-3

导航栏常有「当前页高亮」需求:哪个链接对应的页面正在显示,就给它加个样式。Vue Router 会给「当前激活的链接」自动加上两个 CSS 类:

  • router-link-active:只要网址是链接路径的「前缀」就激活(比如当前在 /aboutto="/" 也会算激活,因为 / 是前缀)。
  • router-link-exact-active:网址和链接路径完全相等才算激活。
<template>
  <nav>
    <NuxtLink to="/" class="router-link-active">首页</NuxtLink>
    <NuxtLink to="/about">关于</NuxtLink>
  </nav>
</template>

<style>
.router-link-active {
  font-weight: bold;
  color: #e11d48;
}
</style>
Tip

如果你不想要「前缀就激活」的行为(比如首页链接在任意页都高亮很烦),可以改用 router-link-exact-active 类,或用 NuxtLinkactive-class / exact-active-class 属性自定义类名。想完全精确匹配,给首页链接加 exact-active-class 即可。

20-4

声明式用标签写死链接,适合静态菜单。但很多跳转是「运行时才决定去哪」的——比如用户提交搜索框,要根据输入拼出网址;或者登录成功后跳回原来那页。这种用代码触发的跳转,叫编程式导航(programmatic navigation),靠 navigateTo 工具函数。

<script setup lang="ts">
const name = ref('')
const type = ref(1)

function navigate () {
  return navigateTo({
    path: '/search',
    query: {
      name: name.value,
      type: type.value,
    },
  })
}
</script>

<template>
  <form @submit.prevent="navigate">
    <input v-model="name" placeholder="关键词" />
    <button type="submit">搜索</button>
  </form>
</template>

navigateTo 接收一个路径字符串,或一个带 path / query 的对象。上面例子会把用户带到 /search?name=xxx&type=1

Warning

调用 navigateTo 时,务必 return 它(或 await 它)。中间件和事件处理函数里不 return,Nuxt 不知道你要跳转,导航就不会发生。这是新手最常踩的坑。

20-5

第 19 章的鉴权中间件其实就是编程式导航的典型场景:不满足就在中间件里 return navigateTo('/login') 把人拦走。两者天然搭配。

20-6

<NuxtLink>navigateTo 在 Nuxt 3 与 Nuxt 4 用法一致。唯一区别是 Nuxt 4 把这些组件/函数统一归到 app/ 体系下,但页面里写标签、函数的方式不变,老代码无需改写。

20-7

<NuxtLink> 只适用于「站内的 Nuxt 路由」。如果你要跳转到别的网站(比如 https://nuxt.com),直接用普通 <a href="..."> 就行——NuxtLink 不会、也不该接管站外链接。其实 NuxtLink 检测到 to 是绝对外链时,也会退化为普通 <a>,但显式写 <a> 语义更清楚。

20-8

默认 <NuxtLink> 会预加载目标页。想关掉某个链接的预加载,加 :prefetch="false"

<template>
  <NuxtLink to="/heavy-page" :prefetch="false">不预加载的大页面</NuxtLink>
</template>

也有 noPrefetch 这种简写属性可用。预加载虽好,但对特别重、又不太会被点到的页面,关掉它能省点流量。

20-9

<NuxtLink> 支持 Vue Router <RouterLink> 的大部分属性。比如 replace 让跳转不留下历史记录(按返回键不会回到上一页),exact-active-class 自定义精确匹配时的类名。需要更细的导航行为时,查 Vue Router 的 RouterLink 文档即可,NuxtLink 都能用。

20-10

前面 navigateTo 用了对象写法。它也能直接吃一个字符串路径:navigateTo('/login')。需要带查询参数或做更复杂控制时才用对象形式。另外,在异步函数(比如 await 一个接口后)里跳转,记着 return await navigateTo(...),确保导航结果被正确传递、不被后续代码覆盖。

Tip

如果你在 onClick 这样的事件里调用,直接 navigateTo(...)return navigateTo(...) 都能工作;放在 definePageMeta 的中间件函数里则必须 return,否则拦截失效。

20-11

表面看 <NuxtLink to="/about"><a href="/about"> 都能跳转,但底层完全不同:

  • 原生 <a> 点击后,浏览器会向服务器重新请求整个页面,整页刷新、白屏一下。
  • <NuxtLink> 点击后,由 Vue Router 在 JavaScript 里拦截这次点击,只去拉「目标页需要的新组件和新数据」,然后无刷新地替换视图。

好处是快、而且不丢全局状态——你登录态、购物车不会因为跳转而重置。代价是:它只对「站内 Nuxt 路由」有效。站外链接、或你确实想整页刷新的场景,还是用原生 <a>

Note

你可以把原生属性直接挂到 NuxtLink 上,比如 <NuxtLink to="/x" target="_blank"> 会新标签打开。NuxtLink 只是 Vue Router <RouterLink> 的封装,RouterLink 支持的属性它基本都接得住。

20-12

点一下 NuxtLink,内部顺序是这样的:Vue Router 先拦下浏览器的默认跳转 → 根据 to 找到目标路由 → 触发第 19 章的路由中间件(如果该页配了的话)→ 跑对应的页面过渡(第 21 章)→ 把新页面渲染进 <NuxtPage> 的出口。全程没有整页刷新,所以你在 app.vue 里写的状态、布局都稳稳保留。这也是为什么 Nuxt 应用点起来像原生 App,而不是传统网页一跳一闪。

20-13

前面讲了 router-link-activerouter-link-exact-active,这里点几个实战里最容易栽的:

  • 坑一:首页 to="/" 在「任何页面」都带 router-link-active,因为 / 是所有路径的前缀。结果首页链接几乎永远高亮。只想在真正首页时高亮,就用 router-link-exact-active,或自己判断 route.path === '/'
  • 坑二:多级导航里,父菜单链接在访问子页时也会高亮(因为 /panel/panel/orders 的前缀)。这通常正是你想要的——表示「当前处在 panel 板块」。但如果只想子页高亮、父菜单不高亮,就得用 exact-active-class 或自己写判断。
  • 坑三:样式被覆盖。你写的 .router-link-active { color: red } 可能被全局 CSS 的优先级压住,不生效。记得检查选择器权重,必要时提高优先级。
Tip

想完全自己掌控高亮逻辑,可以不用这两个自动类,在模板里 :class="{ active: route.path.startsWith('/panel') }",用 route 自己判断,最灵活也最好调。

20-14

两个实用属性值得单独说:

  • replace:跳转时不留历史记录,用户按浏览器「返回」键不会回到上一页。适合「登录成功后跳仪表盘」这种不想让人退回去的场景。
  • custom:不渲染真实的 <a> 标签,而是把导航函数交给你自己用插槽渲染。当你想做一个「点按钮触发跳转、但按钮不是链接」的自定义元素时有用:
<template>
  <NuxtLink to="/dashboard" custom v-slot="{ navigate, href }">
    <button @click="navigate">{{ href }}</button>
  </NuxtLink>
</template>

这里 navigate 是触发跳转的函数,href 是算好的目标地址。你拿它们去渲染任意元素,跳转行为还是 Nuxt 的客户端导航。

20-15

前面说 NuxtLink 会预加载目标页。更具体地说,它预取两样东西:目标页对应的组件代码,以及该页里 useFetch / useAsyncData 声明的接口数据。等你点下去,组件和数据可能已经躺在本地,所以切换近乎瞬时。

这个机制对「列表页 → 详情页」尤其明显:鼠标刚移到链接上,详情数据就开始拉了。如果你的数据很个性化(比如带登录态),Nuxt 也只在客户端做预取,不会在服务端替你乱拉。

Warning

预加载虽好,但页面里堆了几百个 NuxtLink 时,全部预取会瞬间打爆网络。这种长列表场景,用 :prefetch="false" 关掉大部分链接的预取,只对头部几个重要链接保留。

20-16

跳转分两种:静态链接用 <NuxtLink to="...">(客户端无刷新导航、带预加载、可加 active 高亮),动态跳转用 navigateTo(...)(记得 return)。NuxtLink 和原生 <a> 最大区别是「不整页刷新」。下章我们给页面切换加上过渡动画。