简言
记录下nuxt3middleware目录的使用方法。
middleware
middleware是存放路由中间件的文件目录。
路由中间件有三种:
- 匿名(或内联)路由中间件直接在页面中定义。
- 已命名的路由中间件,放在 middleware/ 中,页面使用时通过异步导入自动加载(definePageMeta中的middleware)。
- 全局路由中间件:置于中间件/中,后缀为.global,每次更改路由时都会运行。
中间件名称已规范化为 kebab-case。
路由中间件在 Nuxt 应用程序的 Vue 部分中运行。
使用
路由中间件是导航卫士,接收当前路由和下一条路由作为参数。
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
// In a real app you would probably not redirect every route to `/`
// however it is important to check `to.path` before redirecting or you
// might get an infinite redirect loop
if (to.path !== '/') {
return navigateTo('/')
}
})
Nuxt 提供了两个全局可用的助手,可以直接从中间件返回。
- navigateTo - 重定向到给定路径
- abortNavigation(error?) - 终止导航,可选择错误信息(error)。
nuxt3的路由返回值规则如下:
- nothing (简单返回或根本不返回)- 不会阻止导航,并将移动到下一个中间件函数(如果有的话)或完成路由导航。
- return navigateTo(‘/’) - 重定向到指定路径,如果重定向发生在服务器端,重定向代码将设置为 302 Found。
- return navigateTo(‘/’, { redirectCode: 301 }) - 重定向到指定路径,如果重定向发生在服务器端,重定向代码将设置为 301 Moved Permanently(永久移动)。
- return abortNavigation() - 停止当前导航
- return abortNavigation(error) - 出错时拒绝当前导航
中间件执行顺序
中间件按以下顺序运行:
- 全局中间件
- 页面定义的中间件顺序(如果使用数组语法声明了多个中间件)
例如,假设您有以下中间件和组件:
middleware/
--| analytics.global.ts
--| setup.global.ts
--| auth.ts
<script setup lang="ts">
definePageMeta({
middleware: [
function (to, from) {
// Custom inline middleware
},
'auth',
],
});
</script>
中间件的运行顺序如下:
- analytics.global.ts
- setup.global.ts
- 自定义的内联中间件函数.
- auth.ts
默认情况下,全局中间件根据文件名的字母顺序执行,你可以在文件前面填加数字,以调整运行顺序。
运行时机
如果您的网站是服务器渲染或生成的,那么初始页面的中间件将在页面渲染时执行,然后在客户端再次执行。
如果需要在不同运行时机执行特定代码,则需要process.server或process.client判断:
export default defineNuxtRouteMiddleware((to, from) => {
console.log('中间件auth');
if (process.server) {
console.log('server 运行时机');
}
if (process.client) {
console.log('client 运行时机');
}
const nuxtApp = useNuxtApp();
if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) {
console.log('仅在客户端首次加载时跳过中间件');
}
});
动态添加中间件
可以使用 addRouteMiddleware() 辅助函数手动添加全局或命名路由中间件,例如从插件中添加。
export default defineNuxtPlugin(() => {
addRouteMiddleware('global-test', () => {
console.log('this global middleware was added in a plugin and will be run on every route change')
}, { global: true })
addRouteMiddleware('named-test', () => {
console.log('this named middleware was added in a plugin and would override any existing middleware of the same name')
})
})
在构建时设置中间件
你可以在 pages:extend 钩子中按条件批量添加命名路由中间件,而不是在每个页面上使用 definePageMeta。
import type { NuxtPage } from 'nuxt/schema'
export default defineNuxtConfig({
hooks: {
'pages:extend' (pages) {
function setMiddleware (pages: NuxtPage[]) {
for (const page of pages) {
if (/* some condition */ true) {
page.meta ||= {}
// Note that this will override any middleware set in `definePageMeta` in the page
page.meta.middleware = ['named']
}
if (page.children) {
setMiddleware(page.children)
}
}
}
setMiddleware(pages)
}
}
})
结语
普通的已命名的路由中间件必须在页面的script中注册以下才可以使用:
definePageMeta({
middleware: ['auth'],
});
若出现这样的提示,definePageMeta() is a compiler-hint helper that is only usable inside the script block of a single file component which is also a page. Its arguments should be compiled away and passing it at runtime has no effect.:
说明你的definePageMeta没放对位置,需要放在页面路由生效呈现的vue页面组件的script中。