关键概念
导入功能的提升
Components 文件夹组件自动导入
- 在 Nuxt 中,你可以在 components/ 目录中创建这些组件,它们将自动在整个应用程序中可用,无需显式地导入。
 
Auto-imports 自动导入(响应式 API、生命周期)
1
2
3
4
5
  | 
<script setup lang="ts">
/* ref() and computed() are auto-imported */
const count = ref(1)
const double = computed(() => count.value * 2)
</script>
  | 
 
Built-in Auto-imports 内置自动导入
1
2
3
  | 
<script setup lang="ts">
  /* useFetch() is auto-imported */ const {(data, refresh, status)} = await useFetch('/api/hello')
</script>
  | 
 
Vue.js 路由
1. 通过pages/每个组件生成路由
1
2
3
4
5
  | 
-| pages/
---| about.vue
---| index.vue
---| posts/
-----| [id].vue
  | 
 
2. <NuxtLink>标签进行路由跳转
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | 
<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>
  | 
 
3. Route Parameters 路由参数
1
2
3
4
  | 
<script setup lang="ts">
  const route = useRoute() // When accessing /posts/1, route.params.id will be 1
  console.log(route.params.id)
</script>
  | 
 
4. Route Middleware 路由中间件
- 导航到特定路由之前提取要运行的代码
 
- 路由中间件在 Nuxt 应用程序的 Vue 部分运行。尽管名称相似,但它们与服务器中间件完全不同,后者在应用程序的 Nitro 服务器部分运行。
 
1
2
3
4
5
6
  | 
export default defineNuxtRouteMiddleware((to, from) => {
  // isAuthenticated() is an example method verifying if a user is authenticated
  if (isAuthenticated() === false) {
    return navigateTo("/login");
  }
});
  | 
 
1
2
3
4
5
6
7
8
9
  | 
<script setup lang="ts">
definePageMeta({
  middleware: "auth",
});
</script>
<template>
  <h1>Welcome to your dashboard</h1>
</template>
  | 
 
5. Route Validation 路由验证
- Nuxt 通过你想要验证的每个页面中 
definePageMeta()中的 validate 属性提供路由验证。 
validate 属性接受路由作为参数。您可以返回一个布尔值,以确定这是否是要使用此页面呈现的有效路由。如果返回 false,但找不到其他匹配项,则会导致 404 错误。您也可以直接返回带有 statusCode/statusMessage 的对象,以立即响应错误(不会检查其他匹配项)。 
1
2
3
4
5
6
7
8
  | 
<script setup lang="ts">
definePageMeta({
  validate: async (route) => {
    // Check if the id is made up of digits
    return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id)
  }
})
</script>
  | 
 
Rendering Modes 渲染模式
- 浏览器和服务器都可以解释 JavaScript 代码,以将 Vue.js 组件转换为 HTML 元素。此步骤称为 渲染 。
 
- 默认情况下,Nuxt 使用通用渲染来提供更好的用户体验、性能并优化搜索引擎索引,但您可以在一行配置中切换渲染模式。
 
关于服务端渲染和客户端渲染的一个bug,使用setInterval计时器,服务端报错500
1
2
3
  | 
setInterval(() => {
  request()
}, 3000);
  | 
 
1. 问题分析
当你在 Nuxt 的组件或页面中直接使用 setInterval 时,这段代码会在服务端渲染阶段被执行。然而,setInterval 是浏览器环境中的 API,在服务端(Node.js)环境中会报错,提示类似以下内容:
1
  | 
ReferenceError: setInterval is not defined
  | 
 
2. 解决方案
- 
使用 process.client 判断是否在客户端运行
nuxt 提供了 process.client 变量,用于判断当前代码是否在浏览器环境中运行。你可以通过这个变量确保 setInterval 只在客户端执行。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  | 
// 确保 setInterval 只在客户端运行
if (process.client) {
  const intervalId = setInterval(() => {
    loadData()
  }, 3000)
  // 组件销毁时清除计时器,防止内存泄漏
  onUnmounted(() => {
    clearInterval(intervalId)
  })
}
  | 
 
 
- 
将计时器逻辑放在 mounted 生命周期钩子中
在 Vue.js 中,mounted 钩子只会在客户端渲染完成后执行,因此可以将计时器逻辑放在这里。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
  | 
export default {
  mounted() {
    this.interval = setInterval(() => {
      this.loadData();
    }, 3000);
  },
  beforeDestroy() {
    // 清除计时器,防止内存泄漏
    clearInterval(this.interval);
  },
  methods: {
    loadData() {
      console.log('加载数据...');
    }
  }
};
  | 
 
 
什么是服务器渲染的,什么是客户端渲染的?
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  | 
<script setup lang="ts">
const counter = ref(0); // executes in server and client environments
const handleClick = () => {
  counter.value++; // executes only in a client environment
};
</script>
<template>
  <div>
    <p>Count: {{ counter }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>
  | 
 
在初始请求中,计数器 ref 在服务器中初始化,因为它呈现在 <p>标记内。handleClick 的内容在此处永远不会执行。在浏览器中激活期间,counter ref 会重新初始化。handleClick 最终将自身绑定到按钮;因此,可以合理地推断 handleClick 的主体将始终在浏览器环境中运行。
Universal Rendering 通用渲染
原理
- 当浏览器请求启用了通用渲染的 URL 时,Nuxt 会在服务器环境中运行 JavaScript (Vue.js) 代码,并将完全渲染的 HTML 页面返回给浏览器。如果页面是提前生成的,Nuxt 也可以从缓存中返回完全渲染的 HTML 页面。用户会立即获得应用程序的全部初始内容,这与客户端渲染相反。
 
- 下载 HTML 文档后,浏览器会解释此内容,Vue.js 将控制该文档。曾经在服务器上运行的相同 JavaScript 代码再次在客户端(浏览器)上运行,现在通过将其侦听器绑定到 HTML 来启用交互性(因此是通用渲染)。
 
效果
- 通用渲染允许 Nuxt 应用程序提供快速的页面加载时间,同时保留客户端渲染的优势。此外,由于内容已经存在于 HTML 文档中,因此爬网程序可以毫无开销地为其编制索引。
 
- 通用渲染用途广泛,几乎可以适应任何用例,特别适用于任何面向内容的网站:博客、营销网站、投资组合、电子商务网站和市场。
 
1. 服务器端渲染(SSR)
- 
概念:
- 在 SSR 模式下,页面的 HTML 内容是在服务器端动态生成的,然后发送到客户端。客户端接收到 HTML 后,再通过 JavaScript 进行进一步的交互。
 
- SSR 是 Nuxt 3 的默认渲染模式,适合需要 SEO 优化或需要快速首屏加载的应用。
 
 
- 
好处
- 性能:用户可以立即访问页面的内容,因为浏览器显示静态内容的速度比 JavaScript 生成的内容快得多。同时,Nuxt 在水合过程中保留了 Web 应用程序的交互性。
 
- 搜索引擎优化:通用渲染将页面的整个 HTML 内容作为经典服务器应用程序交付给浏览器。Web 爬虫可以直接为页面的内容编制索引,这使得 Universal rendering 成为您想要快速编制索引的任何内容的绝佳选择。
 
 
- 
缺点
- 开发约束:服务器和浏览器环境不提供相同的 API,因此编写可以在两端无缝运行的代码可能很棘手。幸运的是,Nuxt 提供了指南和特定变量来帮助您确定一段代码的执行位置。
 
- 成本:需要运行服务器才能动态呈现页面。这会增加每月成本,就像任何传统服务器一样。但是,由于浏览器接管了客户端导航的通用渲染,服务器调用大大减少了。利用 edge-side 渲染可以降低成本。
 
 
2. 静态站点生成(Static Site Generation, SSG)
- 在 SSG 模式下,页面的 HTML 是在构建时预先生成的,并作为静态文件部署到服务器。这些静态页面可以在没有服务器端逻辑的情况下直接被客户端加载。
 
- SSG 适合内容不经常更新的网站,如博客或文档网站。
 
3. 单页应用(Single Page Application, SPA)
- 在 SPA 模式下,页面的 HTML 是在客户端动态生成的,服务器只提供一个初始的 HTML 模板和必要的 JavaScript 文件。
 
- SPA 适合对交互性要求较高的应用,但可能对 SEO 不太友好。
 
Client-Side Rendering  客户端渲染
相较于通用渲染相反,不做过多叙述
- 好处
- 开发速度:不考虑服务器的兼容性
 
- 便宜: 不考虑服务器基础设施成本
 
- 离线: 在 Internet 不可用时很好地保持工作
 
 
- 缺点
- 性能: 需等待浏览器下载、解析、运行js,响应长,影响用户体验
 
- 搜索引擎优化: 索引和更新通过客户端渲染交付的内容需要更多时间。不利于引擎爬虫。
 
 
- 您可以在 nuxt.config.ts中使用 Nuxt 启用仅客户端渲染:
 
1
2
3
  | 
export default defineNuxtConfig({
  ssr: false
})
  | 
 
:warning: 如果你确实使用 ssr: false,你还应该放置一个 HTML 文件, ~/app/spa-loading-template.html 其中包含一些你想用来渲染加载屏幕的 HTML,该屏幕将一直呈现,直到你的应用程序被激活。
Deploying a Static Client-Rendered App部署静态客户端呈现的应用程序
Hybrid Rendering  混合渲染
Route Rules  路由规则
Edge-Side Rendering  边侧渲染
Nuxt的Server层服务
通过defineEventHandler()定义接口
server文件夹下定义接 名字channel.get.ts,默认get接口
1
2
3
4
5
6
7
  | 
//  server
//  - /api
// 	  - channel.get.ts
import channel from "~/database/channel" //channel 是database定义的默认数据
export default defineEventHandler(()=>{
    return channel
})
  | 
 
使用useFetch()调用接口
1
2
3
  | 
// 无需导入
// 解构-重命名
const {data:channelList} =await useFetch('/api/channel')
  | 
 
我写过的项目的写法的记录
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  | 
import { API_HOT_CATEGORY_LIST } from '~/api/category'
import { nodeFetch } from '~/server/utils/handle'
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  const data = await nodeFetch(API_HOT_CATEGORY_LIST, { body, nitroEvent: event })
  return {
    data,
    status: 0,
    info: 'ok',
  }
})
  |