useNuxtApp 是一个内置的组合式函数,它提供了一种方式来访问 Nuxt 的共享运行时上下文,也称为Nuxt 上下文,它在客户端和服务器端(但不包括 Nitro 路由中)都可用。它帮助您访问 Vue 应用程序实例、运行时钩子、运行时配置变量和内部状态,例如 ssrContext 和 payload。
<script setup lang="ts">
const nuxtApp = useNuxtApp()
</script>
如果在您的作用域中运行时上下文不可用,调用 useNuxtApp 将抛出异常。您可以改用 tryUseNuxtApp,用于不需要 nuxtApp 的组合式函数,或者只是在不抛出异常的情况下检查上下文是否可用。
provide (name, value)nuxtApp 是一个运行时上下文,您可以使用 Nuxt 插件扩展它。使用 provide 函数创建 Nuxt 插件,使值和辅助方法在您的 Nuxt 应用程序中的所有组合式函数和组件中都可用。
provide 函数接受 name 和 value 参数。
const nuxtApp = useNuxtApp()
nuxtApp.provide('hello', name => `Hello ${name}!`)
// Prints "Hello name!"
console.log(nuxtApp.$hello('name'))
如您在上面的示例中所见,$hello 已成为 nuxtApp 上下文的新自定义部分,并且在所有可以访问 nuxtApp 的地方都可用。
hook(name, cb)nuxtApp 中可用的钩子允许您自定义 Nuxt 应用程序的运行时方面。您可以在 Vue.js 组合式函数和 Nuxt 插件中使用运行时钩子,以挂接到渲染生命周期。
hook 函数对于在特定点通过挂接到渲染生命周期来添加自定义逻辑非常有用。hook 函数主要用于创建 Nuxt 插件时。
有关 Nuxt 调用的可用运行时钩子,请参阅运行时钩子。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('page:start', () => {
/* your code goes here */
})
nuxtApp.hook('vue:error', (..._args) => {
console.log('vue:error')
// if (import.meta.client) {
// console.log(..._args)
// }
})
})
callHook(name, ...args)当使用任何现有钩子调用时,callHook 返回一个 Promise。
await nuxtApp.callHook('my-plugin:init')
useNuxtApp() 暴露了以下属性,您可以使用它们来扩展和自定义您的应用程序,并共享状态、数据和变量。
vueAppvueApp 是全局的 Vue.js应用程序实例您可以通过 nuxtApp 访问。
一些有用的方法
component()- 如果同时传递名称字符串和组件定义,则注册一个全局组件;如果只传递名称,则检索一个已注册的组件。directive()- 如果同时传递名称字符串和指令定义,则注册一个全局自定义指令;如果只传递名称,则检索一个已注册的指令(示例)。use()- 安装一个 Vue.js 插件 (示例)。ssrContextssrContext 在服务器端渲染期间生成,仅在服务器端可用。
Nuxt 通过 ssrContext 暴露以下属性
url (string) - 当前请求 URL。event (h3js/h3请求事件) - 访问当前路由的请求和响应。payload (object) - NuxtApp 有效负载对象。payloadpayload 将数据和状态变量从服务器端暴露给客户端。以下键在从服务器端传递后将在客户端可用
serverRendered (boolean) - 指示响应是否为服务器端渲染。data (object) - 当您使用 useFetch 或 useAsyncData 从 API 端点获取数据时,结果有效负载可以通过 payload.data 访问。此数据被缓存,有助于防止在多次发出相同请求时重复获取数据。<script setup lang="ts">
const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal }))
</script>
export default defineEventHandler((event) => {
return { count: 1 }
})
useAsyncData 获取 count 的值后,如果您访问 payload.data,您会看到 { count: 1 } 记录在那里。ssrcontext 访问相同的 payload.data 时,您也可以在服务器端访问相同的值。state (object) - 当您在 Nuxt 中使用 useState 组合式函数设置共享状态时,此状态数据可通过 payload.state.[name-of-your-state] 访问。export const useColor = () => useState<string>('color', () => 'pink')
export default defineNuxtPlugin((nuxtApp) => {
if (import.meta.server) {
const color = useColor()
}
})
ref、reactive、shallowRef、shallowReactive 和 NuxtError。/**
* This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload.
* You will not have access to the router or other Nuxt-injected properties.
*
* Note that the "DateTime" string is the type identifier and must
* be the same on both the reducer and the reviver.
*/
export default definePayloadPlugin((nuxtApp) => {
definePayloadReducer('DateTime', (value) => {
return value instanceof DateTime && value.toJSON()
})
definePayloadReviver('DateTime', (value) => {
return DateTime.fromISO(value)
})
})
isHydrating使用 nuxtApp.isHydrating (布尔值) 来检查 Nuxt 应用是否在客户端进行水合。
export default defineComponent({
setup (_props, { slots, emit }) {
const nuxtApp = useNuxtApp()
onErrorCaptured((err) => {
if (import.meta.client && !nuxtApp.isHydrating) {
// ...
}
})
},
})
runWithContextrunWithContext 方法旨在用于调用函数并为其提供显式的 Nuxt 上下文。通常,Nuxt 上下文是隐式传递的,您无需担心。然而,在中间件/插件中处理复杂的 async/await 场景时,您可能会遇到异步调用后当前实例被取消设置的情况。
export default defineNuxtRouteMiddleware(async (to, from) => {
const nuxtApp = useNuxtApp()
let user
try {
user = await fetchUser()
// the Vue/Nuxt compiler loses context here because of the try/catch block.
} catch (e) {
user = null
}
if (!user) {
// apply the correct Nuxt context to our `navigateTo` call.
return nuxtApp.runWithContext(() => navigateTo('/auth'))
}
})
const result = nuxtApp.runWithContext(() => functionWithContext())
functionWithContext: 任何需要当前 Nuxt 应用程序上下文的函数。此上下文将自动正确应用。runWithContext 将返回 functionWithContext 的返回值。
Vue.js Composition API(以及类似的 Nuxt 组合式函数)通过依赖隐式上下文工作。在生命周期期间,Vue 将当前组件的临时实例(以及 Nuxt 的 nuxtApp 临时实例)设置为一个全局变量,并在同一个 tick 中将其取消设置。在服务器端渲染时,来自不同用户的多个请求和 nuxtApp 在同一个全局上下文中运行。因此,Nuxt 和 Vue 会立即取消设置此全局实例,以避免在两个用户或组件之间泄漏共享引用。
这意味着什么?Composition API 和 Nuxt Composables 仅在生命周期期间和任何异步操作之前的同一个 tick 中可用
// --- Vue internal ---
const _vueInstance = null
const getCurrentInstance = () => _vueInstance
// ---
// Vue / Nuxt sets a global variable referencing to current component in _vueInstance when calling setup()
async function setup () {
getCurrentInstance() // Works
await someAsyncOperation() // Vue unsets the context in same tick before async operation!
getCurrentInstance() // null
}
经典的解决方案是,在第一次调用时将当前实例缓存到局部变量,例如 const instance = getCurrentInstance(),并在后续的组合式函数调用中使用它,但问题是任何嵌套的组合式函数调用现在都需要显式接受该实例作为参数,而不是依赖于 Composition API 的隐式上下文。这是组合式函数的设计限制,本身不是一个问题。
为了克服这个限制,Vue 在编译我们的应用程序代码时进行了一些幕后工作,并在 <script setup> 的每次调用后恢复上下文。
const __instance = getCurrentInstance() // Generated by Vue compiler
getCurrentInstance() // Works!
await someAsyncOperation() // Vue unsets the context
__restoreInstance(__instance) // Generated by Vue compiler
getCurrentInstance() // Still works!
有关 Vue 实际操作的更好描述,请参阅unjs/unctx#2 (comment).
这就是 runWithContext 可以用于恢复上下文的地方,类似于 <script setup> 的工作方式。
Nuxt 内部使用unjs/unctx来支持类似于 Vue 插件和中间件的组合式函数。这使得像 navigateTo() 这样的组合式函数无需直接传递 nuxtApp 即可工作——为整个 Nuxt 框架带来了 Composition API 的开发体验和性能优势。
Nuxt 组合式函数与 Vue Composition API 具有相同的设计,因此需要类似的解决方案来神奇地进行这种转换。请查看unjs/unctx#2(提案),unjs/unctx#4(转换实现), 和nuxt/framework#3884(集成到 Nuxt)。
Vue 目前仅支持 <script setup> 在 async/await 用法中的异步上下文恢复。在 Nuxt 中,为 defineNuxtPlugin() 和 defineNuxtRouteMiddleware() 添加了转换支持,这意味着当您使用它们时,Nuxt 会自动使用上下文恢复对其进行转换。
unjs/unctx 转换在包含 await 的 try/catch 语句中自动恢复上下文似乎存在 bug,这最终需要解决才能消除上述建议的解决方法的需求。
使用一项新的实验性功能,可以通过Node.js AsyncLocalStorage和新的 unctx 支持来启用原生异步上下文支持,使异步上下文原生适用于任何嵌套的异步组合式函数,而无需转换或手动传递/调用上下文。
此函数与 useNuxtApp 的工作方式完全相同,但如果上下文不可用,则返回 null,而不是抛出异常。
您可以将其用于不需要 nuxtApp 的组合式函数,或者只是在不抛出异常的情况下检查上下文是否可用。
示例用法
export function useStandType () {
// Always works on the client
if (tryUseNuxtApp()) {
return useRuntimeConfig().public.STAND_TYPE
} else {
return process.env.STAND_TYPE
}
}