Nuxt 3 API
该文档主要介绍在 Nuxt 项目中常用的 API
参考
关于 Nuxt 更完整和详细的 API 介绍可以查看官方文档的相应部分
Composables
除了可以使用 Vue 3 所提供的组合式 API,Nuxt 3 还提供了一系列特有的组合式 Composables API
useRoute
参考
该组合式函数 useRoute()
用于获取当前路由对象,只能在 setup
、插件 plugin、路由中间件中调用
提示
在组件的模板中可以使用 $route
访问当前的路由对象
说明
Nuxt 使用 Vue Router 构建和管理前端路由,关于路由对象的详细解释,可以参考 Vue Router 官方文档的相关部分
路由对象具有以下属性:
fullPath
完成的 URL 路径(包括 query 查询内容和 hash 锚点)hash
URL 的锚点(以#
开头的部分)matched
一个数组,包含当前 URL 所匹配到的所有路由记录(而浏览器显示的只是第一个匹配的路由所对应的页面)meta
当前路由所包含的元信息name
当前路由的名称path
URL 的路径部分(不包含协议、query 查询内容、hash 锚点等部分)redirectedFrom
原来的目标路径(假设当前的 URL 是经过了重定向才到达的)query
一个对象,包含 URL 中的查询部分(在?
后面的内容,可以包含多个键值对(用=
相连),它们之间用&
隔开,例如?q=apple&sort=price
)params
一个对象,如果当前 URL 是由动态路由所匹配的,那么动态路由中所设置的参数就会存储在该属性对象中
useRouter
该组合式函数 useRouter()
用于获取应用中的路由实例,只能在 setup
、插件 plugin、路由中间件中调用
提示
在组件的模板中可以使用 $router
访问路由实例
说明
如果项目中具有 📁 pages
目录,则 Nuxt 会采用 Vue Router 来创建和管理路由,所以路由实例的详细解释,可以参考 Vue Router 官方文档的相关部分
如果项目中没有 📁 pages
目录,则该组合式 API useRouter()
会返回一个通用型的路由实例 universal router instance,它和 Vue Router 所提供的路由实例类似,具有类似的方法(但有些方法可能不可用,有些方法的预期行为可能和 Vue Router 所提供的路由实例不一致)
路由实例提供了一些方法用于操作路由
addRoute()
方法:注册一个新的路由,一般用于 Nuxt Plugin 插件中removeRoute()
方法:删除现有的路由getRoutes()
方法:返回一个包含所有路由记录的数组hasRoute()
方法:检查给定名称的路由是否存在resolve(to, currentLocation?)
对给定的路由to
进行解析,并返回一个经过规范化 normalized 的路由对象
路由实例还提供了一些方法实现编程式导航(会同步更改历史记录)
back()
返回前一条历史记录的页面,和router.go(-1)
作用相同forward()
向后一条历史记录移动(如果历史记录列表上还有后一条记录),和router.go()
作用相同go(n)
更灵活地在历史记录中跳转,在 history 记录中向前或者后退n
步push()
导航到指定的 URL,并向 history 栈添加一个新的记录replace()
导航到指定的 URL,但不会向 history 栈添加新记录,而是替换掉当前的 history 记录推荐
更推荐使用 Nuxt 所提供的工具函数
navigateTo()
进行编程式导航
说明
路由实例还提供给一些钩子函数用于设置导航守卫,例如 afterEach()
、beforeEach()
等,但是更推荐采用 Nuxt 所提供的概念 route middleware 路由中间件来实现路由守卫功能,在 📁 middleware
目录中设置路由中间件。
关于 Route Middleware 路由中间件的更多介绍可以查看另一篇笔记《Nuxt 3 项目结构》的 middleware 目录部分
路由导航是一个异步操作,路由实例还提供了一些方法用于处理 Promise 以及可能发生的错误
isReady()
返回一个 Promise 等待路由完成首次导航后 completed the initial navigation 才会 resolveonError()
设置一个错误处理函数,以便捕获路由导航时抛出的错误
数据请求
useAsyncData
组合式 API useLazyFetch(key?, handler, options?)
以异步的方式获取数据,该方法默认会阻碍进行路由导航,直到异步请求的结果返回
该方法可以接收三个参数
- 第一个(可选)参数
key
字符串,表示这一次请求的唯一标识符,用于去重 de-duplicated,如果没有提供就会根据文件名称和该方法所在的行数自动生成一个key
- 第一个参数
handler
是用于获取数据的处理函数(异步函数)
该函数的入参是nuxtApp
即运行时上下文(具体介绍可以查看另一篇笔记《Nuxt 3 简介》) - 第二个(可选)参数
options
是配置对象,可以设置以下属性server
属性:布尔值,是否可以在服务器/后端渲染时调用该方法。
如果设置为false
则该方法只有在客户端才会执行(获取数据),而且在<script setup>
代码块初始化时,数据也依然为null
,要等到应用在前端 hydration complete 生成完成时,才会获取到数据lazy
属性:布尔值,是否采用懒加载方式,即不阻碍路由导航default
方法:工厂函数 factory function,设置默认值(当异步请求返回前,所采取的默认值)transform
方法:对返回的结果进行进一步的转换处理pick
属性:数组,从结果对象中取特定的属性
异步获取的数据会作为页面的 payload,为了提升性能和加快页面的载入,应该通过设置该属性,从返回的结果中只提取出页面所需字段缓存起来vue<script setup> const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] }) // 只提取出 title 和 description 属性的数据 </script> <template> <!-- 该页面只需要使用 title 和 description 的属性值 --> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </template>
watch
属性:监听响应式变量,当它们改变时自动 refresh 发送请求获取新的数据immediate
属性:是否在创建监听器后先立即发送请求获取最新的数据 ❓
该方法的返回值是一个对象
data
属性:结果数据pending
属性:一个布尔值,表示异步函数是否仍在等待结果的状态refresh
或execute
方法:重新调用handler
函数以获取数据说明
默认情况下,Nuxt 会等待
refresh
函数执行完成后,才会执行下一次更新error
属性:当请求失败时所抛出的错误对象
最常见的场景是向后端 API 发送请求获取数据,推荐在处理函数中使用 $fetch
方法发送请求
提示
Nuxt 3 通过 unjs/ofetch
依赖包在全局提供 $fetch
方法,它基于 JavaScript 的原始方法 fetch
,还提供其他一些实用的功能,例如自动对响应返回的 JSON 数据进行反序列化 parse(解构该方法的结果就可用直接使用,不需要再手动进行解析)、兼容服务端渲染(如果用于客户端的代码中,若要请求 Nuxt 应用在服务端设置的 api,可以基于 url 的相对路径发起请求;如果用于服务端的代码中,则模拟发送请求/调用相应的方法获取数据,而不是发起异步请求)
关于 $fetch
的详细介绍参考 Nuxt 官方文档
const { data, pending, error, refresh } = await useAsyncData(
// key
'mountains',
// handler
() => $fetch('https://api.nuxtjs.dev/mountains')
)
提示
针对向后端 API 请求的这种场景,可以使用 useFetch()
方法,它将 useAsyncData()
和 $fetch()
进行封装,专门针对向后端 API 发送请求获取数据的场景,所以只需要传入 URL 即可
useLazyAsyncData
组合式 API useLazyFetch()
也是以异步的方式获取数据,但是该方法默认不会阻碍进行路由导航
注意
由于该方法默认不会阻碍进行路由导航,所以在设计页面时需要考虑处理未获取到数据的情况,可以通过配置对象的属性 default
设置默认数据
说明
其实是对 useAsyncData()
方法的封装,具有相同的函数声明 signature(即函数的参数和返回值的定义相同),并将配置对象的属性 lazy
设置为 true
<template>
<div>
{{ pending ? 'Loading' : count }}
</div>
</template>
<script setup lang="ts">
/**
* Navigation will occur before fetching is complete.
* Handle pending and error states directly within your component's template
*/
const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
// 通过监听 count 等到它获取到数据时再执行相应的操作
watch(count, (newCount) => {
// Because count starts out null, you won't have access
// to its contents immediately, but you can watch it.
})
</script>
useFetch
参考
组合式 API useFetch(url, options?)
将 useAsyncData()
和 $fetch()
进行封装,专门针对向后端 API 发送请求获取数据的场景,所以只需要传入 URL 即可(不需要繁琐地去设置 handler 处理函数,使用 $fetch()
作为 handler),该方法默认会阻碍进行路由导航,直到异步请求的结果返回
<script setup>
const result = await useFetch('/api/count')
</script>
<template>
Page visits: {{ result.data.count }}
</template>
该方法可以接收两个参数
- 第一个参数
url
是需要请求的 API 地址 - 第二个(可选)参数
options
是配置对象,可以设置以下属性key
属性:表示这一次请求的唯一标识符,用于去重 de-duplicatedmethod
属性:请求所使用的方法query
属性:设置查询参数(Nuxt 会使用ufo
依赖包对其进行处理)params
属性:和query
属性一样,别名body
属性:请求体headers
属性:请求头baseURL
属性:base URLserver
属性:布尔值,是否可以在服务器/后端渲染时调用该方法。
如果设置为false
则该方法只有在客户端才会执行(发送请求获取数据),而且在<script setup>
代码块初始化时,数据也依然为null
,要等到应用在前端 hydration complete 生成完成时,才会获取到数据lazy
属性:布尔值,是否采用懒加载方式,即不阻碍路由导航default
方法:工厂函数 factory function,设置默认值(当异步请求返回前,所采取的默认值)transform
方法:对返回的结果进行进一步的转换处理pick
属性:数组,从结果对象中取特定的属性watch
属性:监听响应式变量,当它们改变时自动 refresh 发送请求获取新的数据immediate
属性:是否在创建监听器后先立即发送请求获取最新的数据 ❓
说明
第二个(可选)参数
options
是扩展自unjs/ofetch
依赖包所支持的选项所以除了以上属性,还可以使用
unjs/ofetch
依赖包所提供的选项,例如可以为请求和响应设置拦截器 interceptorstsconst { data, pending, error, refresh } = await useFetch('/api/auth/login', { onRequest({ request, options }) { // Set the request headers options.headers = options.headers || {} options.headers.authorization = '...' }, onRequestError({ request, options, error }) { // Handle the request errors }, onResponse({ request, response, options }) { // Process the response data return response._data }, onResponseError({ request, response, options }) { // Handle the response errors } })
提示
参数 url
和 options
里的各个属性的值,都使用 computed
或 ref
响应式变量,这样当参数发生变化时,该方法会自动执行发送请求,以获取新的数据
说明
该组合式 API 是对 useAsyncData()
方法和 $fetch()
方法的封装,使用起来更简单,直接传入 URL 即可
该方法会自动基于参数 url
和 options
为这一次请求自动生成一个标识符 key
(而 useAsyncData()
方法和 useLazyAsyncData()
方法都需要手动设置)以实现缓存。但是如果参数使用响应式变量或函数(以函数的返回值作为参数值),那么无法自动计算出 key
,需要手动设置该属性才可以利用该方法的缓存/去重 de-duplicate 的优势。
而且会根据所请求的 URL(如果请求的是该应用的服务端 API)推断出响应的数据类型
该方法最后返回值是一个对象
data
属性:响应的结果数据pending
属性:一个布尔值,表示请求是否仍在执行refresh
或execute
方法:重新获取数据说明
默认情况下,Nuxt 会等待
refresh
函数执行完成后,才会执行下一次更新error
属性:当请求失败时所抛出的错误对象
以下是一些示例
- 只读取响应对象中的特定属性ts
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{ // 只读取响应对象的 title 属性 pick: ['title'] })
- 设置请求参数
const param1 = ref('value1')
const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
query: { param1, param2: 'value2' }
})
// 最终请求的 URL 是 https://api.nuxtjs.dev/mountains?param1=value1¶m2=value2
useLazyFetch
组合式 API useLazyFetch()
也是专门针对向后端 API 发送请求获取数据的场景,但是采用「懒加载」的方式,即不会阻碍进行路由导航
注意
该方法默认不会阻碍进行路由导航,所以在设计页面时需要考虑处理未获取到数据的情况,可以通过配置对象的属性 default
设置默认数据
说明
其实是对 useFetch()
方法的封装,具有相同的函数声明 signature(即函数的参数和返回值的定义相同),并将配置对象的属性 lazy
设置为 true
<template>
<!-- you'll need to handle a loading state -->
<div v-if="pending">
Loading ...
</div>
<div v-else>
<div v-for="post in posts">
<!-- do something -->
</div>
</div>
</template>
<script setup lang="ts">
/**
* Navigation will occur before fetching is complete.
* Handle pending and error states directly within your component's template
*/
const { pending, data: posts } = useLazyFetch('/api/posts')
watch(posts, (newPosts) => {
// Because posts starts out null, you won't have access
// to its contents immediately, but you can watch it.
})
</script>
示例
- 重新获取/更新数据
有时候在页面加载数据后,可能需要进行更新,例如服务器的数据可能更新了、用户切换分页、用户使用其他的查询参数等。
虽然可以再一次调用相应的组合式 API 重新发送请求(但是可能因为 de-duplicate 去重的功能,而只读取缓存的数据),更推荐的做法还可以使用以上它们在返回对象中所提供的refresh()
方法说明
默认情况下,调用
refresh()
时会将其他处于 pending 的请求取消掉,以refresh()
的结果作为最新的数据。可以向该方法传入配置对象
refresh({ dedupe: true})
以取消这种默认行为,这样就会采用当前处于 pending 的请求的最终返回结果,作为最新的数据
调用该方法会再次向原有的 URL(如果 URL 是拼接而成的,也是采用当前的参数更新 URL,则不一定与原来的 URL 相同)发送请求,并将获取的的新数据更新到页面上vue<script setup lang="ts"> const page = ref(1); const { data:users, loading, refresh, error } = await useFetch( () => `users?page=${page.value}&take=6`, { baseURL: config.API_BASE_URL } ); // 用户向前或向后翻页时 // 通过调用 refresh() 再次向相应的 URL 发送请求,以获取新的数据 function previous(){ page.value--; refresh(); } function next() { page.value++; refresh(); } </script>
提示
如果页面使用了缓存,可以通过
refreshNuxtData(keys?)
方法强行进行刷新(重新发出请求获取数据)vue<template> <div> {{ pending ? 'Loading' : count }} </div> <button @click="refresh">Refresh</button> </template> <script setup> const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count')) const refresh = () => refreshNuxtData('count') // 可以指定 key 以刷新(在使用 useAsyncData() 和 useLazyAsyncData() 时所设置的 `key`)指定需要刷新的数据 // key 可以是单个字符串,或是一系列字符串构成的数组 // 如果不指定 key 就会刷新当前页面所有通过 useAsyncData()、useLazyAsyncData()、useFetch() 和 useLazyFetch() 方法所获取的数据 </script>
- 清除数据
使用方法clearNuxtData(keys?)
清空该页面使用useAsyncData()
、useLazyAsyncData()
、useFetch()
和useLazyFetch()
方法获取数据时,所产生的缓存、错误信息、pending 状态等
该方法接受(可选)参数key
,它可以是单个字符串,或是一系列字符串构成的数组,以便指定需要清除哪些数据 - 设置请求头
发送请求的一个常见需求是设置请求的头部信息,Nuxt 3 提供了一个组合式 APIuseRequestHeaders()
用于设置请求头vue<script setup> // 在头部添加代理 proxy cookie 以便服务器可以读取与用户相关的信息 ❓ const headers = useRequestHeaders(['cookie']) const { data } = await useFetch('/api/me', { headers }) </script>
注意
并非所有的头部信息都可以安全地绕过 bypassed ,手动设置可能会引入非预期结果。
以下是不应该代理 proxied 的常见头部列表
host
、accept
content-length
、content-md5
、content-type
x-forwarded-host
、x-forwarded-port
、x-forwarded-proto
cf-connecting-ip
、cf-ray
- 附带 Cookie
在 SSR 服务端渲染过程中,其实方法$fetch
只是模拟发送请求(节省性能和带宽 ❓),实际调用相应的方法来获取数据。
所以在 SSR 时需要手动将 Cookie 附加到返回的结果中composables/fetch.tsts// 自定义一个组合式 API // 用于在 SSR 时将头部信息(这里针对的是 cookie)整合到返回的结果中 export const fetchWithCookie = async (event: H3Event, url: string) => { // 使用方法 $fetch.raw() 异步获取数据 const res = await $fetch.raw(url) // 从响应头部中获取 cookies const cookies = (res.headers.get('set-cookie') || '').split(',') for (const cookie of cookies) { // 将这些 cookies 附加到事件对象中 ❓❓❓ appendHeader(event, 'set-cookie', cookie) } // 最后返回响应的数据 return res._data }
vue<script setup lang="ts"> // This composable will automatically pass cookies to the client const event = useRequestEvent() // 异步获取数据,该方法还会将返回的 cookie 设置到页面上 const result = await fetchWithCookie(event, '/api/with-cookie') onMounted(() => console.log(document.cookie)) // 打印出该页面的 cookie </script>
Components
Nuxt 3 提供了一系列内置组件 Build-in Components
NuxtLink 组件
Nuxt 提供一个内置组件 <NuxtLink>
用于处理应用中的链接,其中通过 to
Prop 设置链接的 URL
该内置组件是一种推荐的「替代品」,用于替代 Vue Router 所提供的组件 <RouterLink>
和 HTML 原生元素 <a>
它会根据链接指向的目标是内部页面还是外部链接,采取不同的优化措施,如对目标页面进行预取 prefetching 处理
<template>
<!-- 指向外部页面 -->
<NuxtLink to="https://nuxtjs.org">
Nuxt website
</NuxtLink>
<!-- 最终渲染生成 <a> 元素 -->
<!-- <a href="https://nuxtjs.org" rel="noopener noreferrer">...</a> -->
<!-- 指向内部页面,使用相对路径 -->
<!-- 最终同样渲染为 <a> 元素 -->
<!-- 但指向内部页面的链接会由 Vue Router 管理 -->
<!-- 并进行 prefetching 优化 -->
<NuxtLink to="/about">
About page
</NuxtLink>
</template>
该组件可以设置的 Props
to
属性:设置链接 URL,也可以是一个 route location object 表示路由路径的对象href
属性:它是to
属性的别名,如果组件设置了to
属性,则该 Prop 会忽略target
属性:设置锚标签的target
属性rel
属性:设置锚标签的rel
属性。对于外部链接,默认值是noopener noreferer
activeClass
属性:当链接「激活时」,即该链接和当前页面的路由(部分)匹配时,则为锚标签添加该 Prop 所指定的 class 类名。默认添加router-link-active
(这是是 Vue Router 的默认值)exactActiveClass
属性:当链接和当前页面的路由完全匹配时,则为锚标签添加该 Prop 所指定的 class 类名。默认添加router-link-exact-active
(这是 Vue Router 默认值)replace
属性:以取代模式打开链接,即不会向 history 栈添加新记录,而是替换掉当前的 history 记录external
属性:布尔值,如果设置为true
则强制将该链接视作外部链接;如果设置为false
则强制将该链接视作内部链接。用于处理一些特别的情况prefetch
属性和noPrefetch
属性:是否在链接进入视口时进行预取处理prefetchedClass
属性:对已经完成预取处理的链接添加 class 类名custom
属性:布尔值,是否将该组件渲染为一个<a>
标签,以便让开发者对该组件进行扩展。例如(通过v-slot
指令获取该组件「抛出」的数据)自定义组件的模板,有更大的自由度控制该组件的外观和行为
提示
Nuxt 提供了方法 defineNuxtLink()
可以创建一个属于自己的链接组件
export default defineNuxtLink({
// (可选属性)组件名称
componentName: 'MyNuxtLink',
// (可选属性)对于外部链接设置 `rel` 属性,以下是默认值
externalRelAttribute: 'noopener noreferrer',
// (可选属性)当链接与当前页面的路由(部分)匹配时,添加的 class 类名
// 以下是默认值
activeClass: 'router-link-active',
// (可选属性)当这则是完全匹配时,添加的 class 类名,以下是默认值
exactActiveClass: 'router-link-exact-active',
// (可选属性)对已经完成预取处理的链接添加 class 类名
prefetchedClass: '',
// (可选属性)是否在 `href` 所指定的链接后添加 / 斜杠
// 可以设置为 'append' 表示添加;也可以设置为 'remove' 表示移除
trailingSlash: 'append'
})
Teleport 组件
内置组件 <Teleport>
可以将其内容指定渲染到页面的任意位置
通过该组件的 Prop to
指定需要渲染到页面哪个元素内,该属性值可以是一个表示 CSS 选择器的字符串,或是一个 DOM 元素
Nuxt 在 SSR 服务端渲染时也支持使用该组件,但只能将它指定渲染到 <body>
元素内,且作为直接子元素
<template>
<button @click="open = true">
Open Modal
</button>
<!-- Teleport 渲染到 body 内,所以该组件可以在客户端渲染,也可以在服务端渲染 -->
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">
Close
</button>
</div>
</Teleport>
</template>
如果是想指定到其他容器内,则需要约束该元素仅在客户端渲染,可以使用 Nuxt 的内置组件 <ClientOnly>
组件来包裹 <Teleport>
<template>
<ClientOnly>
<Teleport to="#some-selector">
<!-- content -->
</Teleport>
</ClientOnly>
</template>
Utils
Nuxt 3 提供了一系列使用的工具函数 Utils Functions
definePageMeta
definePageMeta()
方法用于为页面(位于 📁 pages
目录里的组件)添加元信息
注意
由于 definePageMeta()
方法是一个编译器函数 compiler macro,所以它是先于 Vue 执行的,因此不能访问当前页面/组件以及里面定义的变量,但可以访问导入到页面的其他值
该方法可以为页面添加任何额外的信息,但是有些字段是预留的用于配置 Nuxt 的特定的功能
alias
属性:字符串或字符串数组,为该页面设置路由别名,这样就可以通过不同的 URL 来访问该页面,例如对于pages/users/[id].vue
的页面,可以为其设置别名为/u/:id
(⚠️ 如果是页面是由动态路由所匹配的,那么别名中的路由也需要采用相同的 param 参数)keepalive
属性:如果将其属性值设置为true
,则 Nuxt 会为页面组件外包裹一个 Vue 内置组件<keepAlive>
,在路由切换时会保留该页面的状态。该属性值还可以是一个对象,会作为 Props 传递给<KeepAlive>
以便对该组件进行更详细的配置。layout
属性:设置该页面使用哪个布局模板layoutTransition
属性:为该页面设置布局更改的过渡动效middleware
属性:为该页面设置专属的路由中间件pageTransition
属性:为该页面设置页面切换的过渡动效redirect
属性:将页面重定向到其他路由。重定向会在路由守卫之前执行validate
属性:对路由进行验证,是否可以执行页面渲染(特别是对于由动态路由所匹配的页面),实现一个简单的路由守卫key
属性:该页面组件的唯一标识符
navigateTo
navigateTo(to, options?)
方法是一个 router 路由实例的工具函数,可以实现编程式导航。它在客户端和服务端都可用,也可以用于插件和模块中
该方法可接受两个参数
- 第一个参数
to
:导航的目标路径或路由对象,默认为/
- 第二个(可选)参数
options
:是一个配置对象,具有以下可选属性replace
属性:布尔值,是否采用取代的模式执行导航操作,即不会向 history 栈添加新记录,而是替换掉当前的 history 记录redirectCode
属性:数值,当在服务端发生重定向时返回的响应码,默认值为302
external
属性:布尔值,是否允许导航到外部链接,如果设置为false
(默认值)且导航的 URL 为外部链接时就会抛出错误
说明
该方法是一个异步函数,如果需要在导航后执行特定的操作,需要使用 async-await 结构,或使用链式调用的方式