小试牛刀
在nuxt中,定义路由非常简单
在app目录下创建一个pages目录,然后里面的vue文件就是路径
nuxt4之前的版本,pages目录是在项目根目录下的,新版本之后是需要放在app目录下
判断是不是新版本,就看脚手架创建的这个项目,有没有app目录就知道了
举个例子
app
pages
about.vue
article
index.vue
app.vue
对应about.vue的访问路径就是 /about
对应article/index.vue的访问路径就是 /article
需要把app.vue改一下
<script setup lang="ts">
</script>
<template>
<div>
<nuxt-page></nuxt-page>
</div>
</template>
重点就是使用 nuxt-page组件
这个组件会自动发现pages下面的vue组件
SSR vs CSR 渲染流程
- 服务端渲染 (SSR): 所有的内容(标题、段落、数据)在离开服务器之前就已经填入到 HTML 页面中。浏览器拿到的是一个已经可以阅读的完整文档,右键“查看网页源代码”能看到完整内容。
- 客户端渲染 (CSR): 页面本身是一个空的“骨架”,内容需要依靠 JavaScript 在用户浏览器(客户端)内执行并请求数据后才能显示。右键“查看网页源代码”只能看到一个空的占位符。

| 特性 | SSR (Nuxt 默认) | CSR (传统 SPA) |
|---|---|---|
| SEO 搜索引擎优化 | 极好。爬虫直接读取完整 HTML。 | 较差。爬虫看到的是空壳。 |
| 首屏加载速度 (FCP) | 快。内容随 HTML 一起到达。 | 慢。需等 JS 下载并执行完。 |
| 服务器压力 | 大。服务器要负责实时生成页面。 | 小。服务器只负责传文件。 |
| 用户体验 | 页面跳转有时会有短暂白屏。 | 初次加载慢,但后续页面切换极快。 |
动态路由
像文章详情,用户详情这些页面,并不是一个页面,而是动态的页面
访问路径大概是这样的
/article/1
/article/2
这就需要我们在定义的时候,做一些特殊处理
app
pages
about.vue
article
[id].vue
app.vue
然后在[id].vue里面
<script setup lang="ts">
import {useRoute} from "vue-router";
const route = useRoute()
const articleId = route.params.id
</script>
<template>
<div>
文章详情页面: 文章id {{ articleId }}
</div>
</template>
definePageMeta
对于动态路由[id].vue,如果用户访问/article/abc(id 应该是数字),页面可能会崩溃或显示异常。
definePageMeta({
validate: async (route) => {
// 检查 id 是否为数字
return /^\d+$/.test(route.params.id as string) // 匹配失败会跳转到404页面
}
})
多个路由参数?
/article/1/comment/1
pages
article
[articleID]
comment
[commentID].vue
[id].vue
index.vue
特殊的页面 表示 /
pages/index.vue 表示 /
pages/user/index.vue 表示 /user
那pages/user.vue 表示?
嵌套路由
如果存在pages/parent.vue和pages/parent/child.vue,那么parent.vue内部也需要一个<NuxtPage />来承载子页面内容。
useHead用法
专门用来管理页面元数据(Metadata)。
简单来说,它的作用就是让你在 Vue 组件中,动态地修改 HTML 文档里的<head> 部分。比如修改网页标题、添加 CSS 链接、插入脚本
修改title
希望访问不同的页面,网站的title有不同的变化,需要使用nuxt给我们提供的useHead 函数
<script setup lang="ts">
// 直接写就行,这些声明已经在.nuxt里面了
useHead({
title: '关于我们 - 枫枫知道的网站',
meta: [
{ name: 'description', content: '这是关于页面的描述,对 SEO 非常友好' }
]
})
</script>
<template>
<div>
<h1>关于页面</h1>
<p>hello, 这是一个 SSR 渲染的页面</p>
</div>
</template>
<style scoped>
/* 你的样式 */
</style>
优先级:如果页面有useHead的配置,就用自己的,没有就找父级,直到app.vue
如果你的编辑器看到useHead 这些爆红的话,改一下tsconfig.json,或者升级webstoram版本
{
"extends": "./.nuxt/tsconfig.json", // 强制让编辑器读取主配置
"files": [],
"references": [
{ "path": "./.nuxt/tsconfig.app.json" },
{ "path": "./.nuxt/tsconfig.server.json" },
{ "path": "./.nuxt/tsconfig.shared.json" },
{ "path": "./.nuxt/tsconfig.node.json" }
]
}
- 管理复杂的body和html属性
有时候你需要在特定的页面给<body>标签加个类名(比如暗黑模式或特定背景),或者修改<html>的语言属性,useHead也能轻松搞定:
useHead({
htmlAttrs: {
lang: 'zh-CN'
},
bodyAttrs: {
class: 'article-theme-dark'
}
})