pages 页面
默认情况下,Nuxt 会将 app.vue 视为入口点并为应用程序的每个路由呈现其内容。
pages目录是可选的,这意味着如果只使用 app.vue 就不会包含 vue-router,从而减少你的应用程序的包的大小。当然,大多数情况下应该都是需要 pages 目录的。
页面是Vue组件,可以使用 .vue、.js、.jsx、.ts、.tsx、.mjs 等扩展名
Nuxt.js 依据 pages 目录结构自动生成 vue-router 模块的路由配置,使用
:::danger
由于Nuxt 3在内部使用了
添加首页
新建 src/pages 目录,再新建 index.vue 首页,pages/index.vue
文件映射应用程序的路由是:/
<template>
<div>
<h1>nuxt3 app home</h1>
</div>
</template>
修改 src/app.vue
入口
<template>
<div>
<!-- 路由出口 -->
<NuxtPage></NuxtPage>
</div>
</template>
可以看到页面更新
单个根元素
页面必须具有单个根元素,以允许页面之间的路由转换。(HTML注释也被视为元素。)
这意味着,当路由被服务器渲染或静态生成时,将能够正确地看到它的内容,但当在客户端导航时向该路由导航时,路由之间的转换将失败,将看到该路由不会被渲染。
下面是一些例子,说明一个有单一根元素的页面是什么样子:
<template>
<div>
<!-- 这个页面只有一个单一的根元素 -->
Page content
</div>
</template>
<template>
<!-- 因为注释也被视为元素,有多个根元素在客户端导航期间路线更改时不会被渲染 -->
<div>Page content</div>
</template>
<template>
<div>This page</div>
<div>有多个根元素</div>
<div>在客户端导航期间路线更改时不会被渲染</div>
</template>
添加页面静态路由
添加一个 about 页面,添加 src/pages/about/index.vue
文件
<template>
<div>
<h1>nuxt3 about page</h1>
</div>
</template>
在 src/pages/index.vue
配置路由跳转
<template>
<div>
<h1>nuxt3 app home</h1>
<NuxtLink to="/about">进入关于页</NuxtLink>
</div>
</template>
点击链接跳转
添加页面动态路由
动态路由顾名思义就是这个路由地址是可变的,是动态的;使用场景比较常见的就是文章的详细页,一般一篇文章会有对应的一个 id,那这个 id 就是动态的;
如果想让一个参数是可选的,必须用[]
把它括起来,例如:~/pages/[slug]/index.vue或~/pages/[slug].vue
新建新建 src/pages/[id]
目录,再新建 src/pages/[id]/index.vue
文件;
<template>
<div>
<p>随随便便</p>
</div>
</template>
或者 src/pages/articles
目录, 再新建 [id].vue
文件
然后修改 pages/index.vue
<template>
<div>
<h1>nuxt3 app home</h1>
<ul>
<li><NuxtLink to="/about">进入关于页</NuxtLink></li>
<li><NuxtLink to="/1">[目录] 1</NuxtLink></li>
<li><NuxtLink to="/articles/2">articles 2</NuxtLink></li>
</ul>
</div>
</template>
嵌套路由
你的文件名和目录同名 nuxt3 就会自动给你制造成嵌套路由,父组件中使用
比如下面目录结构:
-| pages/
---| parent/
------| child.vue
---| parent.vue
<template>
<div>
<h1>parent 目录 child.vue</h1>
</div>
</template>
要显示组件,需要在父级中添加
<template>
<div>
<h1>嵌套路由示例 - 父级 parent.vue 页面</h1>
<NuxtPage />
</div>
</template>
http://localhost:3000/parent/child
想要直接访问 /parent 可以在 parent 目录下新建一个 index.vue。
不过这里有个问题,点击浏览器刷新按钮时,index.vue 的内容会在parent.vue之后显示;而 child.vue 和parent.vue 的内容是同时显示的
<template>
<div>
<h1>parent 目录 index.vue 页面</h1>
</div>
</template>
路由跳转
在页面之间导航,使用
在 vue 实例中,可以使用 navigateTo 进行导航
<template>
<div>
<h1>nuxt3 app home</h1>
<ul>
<li><NuxtLink to="/about">进入关于页</NuxtLink></li>
<li><NuxtLink to="/1">[目录] 1</NuxtLink></li>
<li><NuxtLink to="/articles/2">articles 2</NuxtLink></li>
<li @click="navigate">编程式导航</li>
</ul>
</div>
</template>
<script setup>
const name = ref('');
const type = ref(1);
function navigate(){
return navigateTo({
path: '/about',
query: {
name: name.value,
type: type.value
}
})
}
</script>
definePageMeta 页面元数据
interface PageMeta {
validate?: (route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>
redirect?: RouteRecordRedirectOption
alias?: string | string[]
pageTransition?: boolean | TransitionProps
layoutTransition?: boolean | TransitionProps
key?: false | string | ((route: RouteLocationNormalizedLoaded) => string)
keepalive?: boolean | KeepAliveProps
layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey>
middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>
[key: string]: any
}
validate
name 页面路由名称
alias 页面别名
从不同的路径访问同一页面。它可以是一个字符串,也可以是一个字符串数组
keepalive
Nuxt 会自动将的页面包装在 Vue
<script setup>
definePageMeta({
keepalive: true
})
</script>
layout 指定页面布局
定义用于呈现路由的布局。这可以是 false(禁用任何布局)、字符串或 ref/computed
middleware 路由中间件
<script setup>
definePageMeta({
middleware: [
function (to, from) {
// Custom inline middleware
},
'auth',
],
});
</script>
自定义元数据
declare module '#app' {
interface PageMeta {
pageType?: string
}
}
// It is always important to ensure you import/export something when augmenting a type
export {}
路由
useRoute() 路由参数
使用 useRoute() 获取当前路由信息。
上面的动态路由例子中,页面内容是写死的,在 url 中修改 id,页面都是相同的内容,可以使用 useRoute() 获取路由参数,动态更改页面内容
在src/pages/articles/[id].vue
中添加
<script lang="ts" setup>
const route = useRoute();
console.log("🚀 ~ file: [id].vue:9 ~ route:", route);
</script>
打印查看 route 信息
修改 src/pages/articles/[id].vue
<template>
<div>
<p>页面id {{ route.params.id }}</p>
</div>
</template>
<script lang="ts" setup>
const route = useRoute();
console.log("🚀 ~ file: [id].vue:9 ~ route:", route);
</script>
页面显示 id
路由中间件
中间件允许您定义一个自定义函数运行在一个页面或一组页面渲染之前。
路由中间件在 Nuxt 应用程序的 Vue 中运行。尽管名称相似,但它们与服务器中间件完全不同,后者运行在应用程序的 Nitro 服务器中。
路由中间件类型
路由中间件有三种:
- 匿名(或内联)路由中间件,直接在使用它们的页面的 definePageMeta 中定义。
- 命名路由中间件,放置在
middleware/
目录中,在页面上使用时将通过异步导入自动加载。(注意:路由中间件名称规范化为 kebab-case) - 全局路由中间件,放置在
middleware/
目录中,带有.global
后缀,并将在每次路由更改时自动运行。
export default defineNuxtRouteMiddleware((to, from) => {
// isAuthenticated() is an example method verifying if a user is authenticated
if (isAuthenticated() === false) {
return navigateTo('/login')
}
})
<script setup>
definePageMeta({
middleware: 'auth'
})
</script>
格式
路由中间件接收当前路由和下一个路由作为参数的导航防护。
export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
return navigateTo('/')
})
Nuxt提供了两个全局可用的帮助程序,可以直接从中间件返回:
navigateTo (to: RouteLocationRaw | undefined | null, options?: { replace: boolean, redirectCode: number, external: boolean )
- 重定向到插件或中间件中的给定路由。也可以直接调用它来执行页面导航。abortNavigation (err?: string | Error)
- 中止导航,并显示可选的错误消息。
与vue-router
文档中的导航卫士不同,第三个next()参数不被传递,重定向或路由取消是通过从中间件返回一个值来处理的。可能的返回值为:
- nothing - 不阻止导航,并将移动到下一个中间件函数,如果有的话,或者完成路由导航。
- return navigateTo(‘/‘) 或 return navigateTo({ path: ‘/‘ }) - 重定向到给定的路径,如果重定向发生在服务器端,将设置重定向代码为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>
definePageMeta({
middleware: [
function (to, from) {
// Custom inline middleware
},
'auth',
],
});
</script>
执行顺序为
- analytics.global.ts
- setup.global.ts
- 自定义内联中间件
- auth.ts
:::info 默认情况下,全局中间件根据文件名按字母顺序执行。有时可能需要定义特定顺序。建议在全局中间件前面加上“字母顺序”编号 :::
middleware/
--| 01.setup.global.ts
--| 02.analytics.global.ts
--| auth.ts
动态添加中间件
使用插件动态添加路由中间件
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')
})
})
路由验证
Nuxt通过definePageMeta validate
属性提供路由验证
如果您有更复杂的用例,则可以改用匿名路由中间件
<script setup>
definePageMeta({
validate: async (route) => {
// Check if the id is made up of digits
return /^\d+$/.test(route.params.id)
}
})
</script>
自定义路由
路由默认根据 pages 目录自动生成