你好同学,我是沐爸,欢迎点赞、收藏、评论和关注。
Nuxt 的一个核心功能是文件系统路由器,路由是根据文件自动注册的,Nuxt 为在 pages/ 目录下的每个 Vue 文件 创建相应的路由(或 URL)。
一、用法
页面是 Vue 组件,可以具有 Nuxt 支持的任何有效扩展,默认情况下是 .vue,也可以是 .js .jsx .mjs. ts .tsx
Nuxt 将自动为 pages 目录的下每个页面创建一个路由。
pages/index.vue
html
<template>
<h1>Index page</h1>
</template>
pages/index.ts
ts
// 渲染函数
export default defineComponent({
render() {
return h("h1", "Index page");
},
});
pages/index.tsx
tsx
export default defineComponent({
render() {
return <h1>Index page</h1>;
},
});
生成的路由文件:
javascript
{
"routes": [
{
"path": "/",
"component": "pages/index.vue"
}
]
}
如果您正在使用 app.vue,请确保使用组件以显示当前页面:
html
<template>
<div>
<NuxtPage />
</div>
</template>
页面 必须具有单个根元素,以允许页面之间的路由转换。
二、导航
要在应用程序的页面之间导航,你应该使用 <NuxtLink>
组件。此该组件属于 Nuxt 默认组件,因此不用导入,可以直接使用。
app.vue
html
<template>
<header>
<nav>
<ul>
<li><NuxtLink to="/about">About</NuxtLink></li>
<li><NuxtLink to="/posts/1">Post 1</NuxtLink></li>
<li><NuxtLink to="/posts/2">Post 2</NuxtLink></li>
</ul>
</nav>
</header>
</template>
三、编程式导航
除了使用 <NuxtLink>
组件进行导航,也可以使用 navigateTo
进行编程式导航。
ts
<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>
四、路由参数
使用 useRoute()
可以在 Vue 组件中访问当前路由的详细信息。
html
<script setup lang="ts">
const route = useRoute();
// 当访问 /posts/1 时, route.params.id 将会是1
console.log(route.params.id);
</script>
四、动态路由
如果你在方括号内放置任何内容,它将被转换为动态路由参数。
如果希望参数是可选的,则必须将其括在双方括号中。
markdown
-| pages/
---| index.vue
---| users-[group]/
-----| [id].vue
鉴于上面的示例,你可以通过 $route 对象访问组件中的 group/id。
pages/users-[group]/[id].vue
html
<template>
<p>{{ $route.params.group }} - {{ $route.params.id }}</p>
</template>
<script setup lang="ts">
const route = useRoute();
console.log(route.params.group); // group
console.log(route.params.id); // id
</script>
如果导航到 /users-admins/123,页面将显示:
html
<template>
<p>admins - 123</p>
</template>
<script setup lang="ts">
const route = useRoute();
console.log(route.params.group); // admins
console.log(route.params.id); // 123
</script>
五、嵌套路由
注意使用 <NuxtPage>
组件来渲染子页面。
目录结构:
markdown
-| pages/
---| parent/
------| child.vue
---| parent.vue
生成的路由文件:
javascript
[
{
path: "/parent",
component: "~/pages/parent.vue",
name: "parent",
children: [
{
path: "child",
component: "~/pages/parent/child.vue",
name: "parent-child",
},
],
},
];
pages/parent.vue
html
<template>
<div>
<h1>I am the parent view</h1>
<NuxtPage :foobar="123" />
</div>
</template>
pages/parent/child.vue
html
<script setup lang="ts">
const props = defineProps(["foobar"]);
console.log(props.foobar);
</script>
六、路由元信息
你可能希望为应用程序中的每个路由定义元数据,可以使用 definePageMeta()
宏 执行此操作。该函数接受一个对象,meta 是其中的一个属性。
ts
definePageMeta({
meta: {
title: "My Page",
description: "This is my page",
},
});
然后,可以在应用程序的其余部分使用 route.meta
访问此数据。
ts
<script setup lang="ts">
const route = useRoute() console.log(route.meta.title) // My home page
</script>
七、路由中间件
Nuxt 提供了一个可自定义的路由中间件框架,你可以在整个应用程序中使用,非常适合在导航到特定路由之前提取要运行的代码。
路由中间件有三种:
- 匿名(或内联)路由中间件,直接在使用它们的页面中定义。
- 命名路由中间件,它们被放置在 middleware/ 目录中,当在页面上使用时,将通过异步导入自动加载。(注意:路由中间件名称被规范化为 kebab-case,因此 someMiddleware 将被转换为 some-middleware)。
- 全局路由中间件,它们被放置在 middleware/ 目录(带后缀),并将在每次路由更改时自动运行。
自定义内联中间件
ts
<script setup lang="ts">
definePageMeta({
middleware: [
function (to, from) {
// 处理逻辑
},
'auth'
]
})
</script>
命名路由中间件:pages/index.vue
html
<script setup lang="ts">
definePageMeta({
middleware: "auth",
});
</script>
<template>
<h1>Welcome to your dashboard</h1>
</template>
全局路由中间件:middleware/auth.ts
ts
export default defineNuxtRouteMiddleware((to, from) => {
// 检查用户是否登录
if (!isAuthenticated) {
return navigateTo("/login");
}
});
八、路由验证
Nuxt 可以通过 definePageMeta() 中的 validate 方法验证每个页面。
该属性接受 route 作为参数。你可以返回一个布尔值,以确定路由是否合法。
这是否是要使用此页面呈现的有效路由。如果返回 ,但找不到另一个匹配项,则会导致 404 错误。您也可以直接返回带有 / 的对象,以立即响应错误(不会检查其他匹配项)。validateroutefalsestatusCodestatusMessage
如果您有更复杂的用例,则可以改用匿名路由中间件。
pages/posts/[id].vue
html
<script setup lang="ts">
definePageMeta({
validate: async (route) => {
// 对 id 进行校验
return (
typeof route.params.id === "string" && /^\d+$/.test(route.params.id)
);
},
});
</script>
好了,分享结束,谢谢点赞,下期再见!