【Nuxt】相关学习(一)
了解
Nuxt3 是基于 Vue3 的一个框架,它提供了一些开箱即用的功能,如路由、状态管理、服务器端渲染等,可以帮助开发者快速构建高性能的 Vue 应用。
为什么要学习?工作需要,SSR 顺便了解下,写篇博客记录一下
优点:
- 支持 Vue3 & Vite
- 更好的 SEO 搜索引擎优化
- 提高开发效率(官网这么说,上手试试)
- 自动化路由
- 支持多种部署方式
- 服务端渲染
- 静态化生成
SPA 单页应用
single page application 单页应用,一般也称为客户端渲染 CSR client side Render。整个站点由一个 HTML 页面构成, 所有内容通过 JS 动态加载和渲染。一般的,用户在访问 SPA 站点,页面只有第一次加载会请求资源,后续都是通过 AJAX 异步请求获取数据并动态更新页面。
存在问题:
- 首屏加载慢(白屏问题),加载大量 JS 和 CSS 文件
- SEO 不友好(相对)搜索引擎无法直接抓取页面内容
- 内存占用高,会在内存中缓存大量数据
SSR 服务端渲染
将客户端渲染和服务端渲染结合起来,主要是在服务端生成好 HTML (结构和内容)代码,并将其发送到浏览器端
优点:
- 性能相对好,首屏更快
- SEO 友好
- 用户体验佳
- 内存占用相对低
缺点:
- 开发复杂度增加
- 服务器负载增加
- 需要更多的服务器资源
SSG 静态化生成
静态化生成 Static Site Generation,在构建时生成静态 HTML 文件,并将这些文件部署到静态文件服务器上。用户访问时,直接返回生成的静态文件,无需服务端参与。
优点:
- 性能最好,首屏最快
- SEO 友好
- 用户体验最好
- 内存占用最低
- 部署简单
缺点:
- 内容更新需要重新构建
- 频繁改动的场景不适合
Nuxt 基础
https://nuxt.com/docs/getting-started/upgrade
Nuxt3
- nuxt3 默认使用 vite 构建,也支持 webpack
- 内置官方自研服务器引擎 Nitro
- 全面支持 ES6 模块化
- 更好地支持 Vue3 Composition API 也兼容 Vue2 Options API
- TS 支持更完善
开发环境
- nodejs 18+
- npm 8+
- pnpm 8+
- vue 3.0+
- vite 3.0+
- typescript 4.0+
npx nuxi@latest init learn-nuxt
pnpm install
pnpm run dev
UI 库
- element antd 这些随便选,按官网来就好
pnpm add ant-design-vue@4
配置按需加载
pnpm add unplugin-vue-components -D
这里就直接把 nuxt.config.ts 配置帖上来 了
1 | import Components from 'unplugin-vue-components/vite' |
页面
在 Nuxt3 中,页面是指应用程序中的路由页面,这些页面可以被搜索引擎索引并直接通过 url 访问。页面由 Vue 组件构成,并且可以在 pages 目录下创建
app.vue 是最顶级入口,要这样用需改动一下,添加 NuxtPage
Nuxt 的内置组件
组件
我们可以在根目录下创建 components 目录来存放组件,不需导入和注册即可直接使用
路由
Nuxt3 路由基于 vue-router 并通过文件目录结构来自动生成
而动态路由,可以用 [dynamic]
定义动态路由,如果是可选参数可以用 [[dynamic]]
动态路由及参数获取
如图创建目录 users-[group]
及文件 [id].vue
1 | <template> |
嵌套路由的使用
在 pages 目录下创建一个 parent.vue 文件。如果我们想使用子路由的形式, http://localhost:3000/parent/child
需要继续创建 pages/parent 目录,然后添加对应文件即可,如 pages/parent/child.vue。 页面访问照旧,现在 http://localhost:3000/parent/child 就可以访问到子路由了
路由跳转
用内置的 NuxtLink 即可 (基本同 router-link)
用自定义事件跳转
1 | <template> |
路由中间件
Nuxt3 提供了一个路由中间件,允许在路由跳转前后执行特定代码,如页面访问权限验证,记录用户的访问记录等(路由拦截、路由守卫) 我们可以在项目根目录下创建 middleware 目录来存放中间件
- 命名路由中间件
防止在 middleware 中,在页面上使用会通过异步导入自动加载
- 匿名(或内联)路由中间件
直接在使用的页面中定义
- 全局路由中间件
放在 middleware 中(带有 .global
后缀)并将在每次路由更改时自动运行
- 用法(命名路由中间件)
路由中间件是一个导航守卫,它接受当前路由和下一个路由作为参数
1 | export default defineNuxtRouteMiddle((to, from) => { |
about.vue
1 | <script setup> |
通过 Nuxt 内置函数,definePageMeta,传入我们要加入的中间件,现在我们访问 /about (由于未登录),会自动跳转到 /login
如果页面很多,有的只需要做下简单判断,没必要都写 middleware 里,这时就可以用匿名路由中间件,同上,只是写到组件里
1 | <!-- about.vue --> |
- 全局路由中级件
middleware > run.global.ts 只要定义了该文件,应用内路由跳转时就会自动执行
1 | export default defineNuxtRouteMiddleware((to, from) => { |
Nuxt 插件
Nuxt3 中,插件是一种在构建时注册和使用的模块,可以用于处理常规的 JS 一来和特殊的框架配置,同时也可以与 Nuxt 项目一起发布
只有在 plugins 目录的顶层文件(或任何子目录的索引文件)才会被注册为插件,例如:
- plugins/myPlugins.ts 注册
- plugins/Aplugins/index.ts 注册
- plugins/Bplugins/file.ts 不会被注册
1 | export default defineNuxtPlugin(() => { |
用法 1:作为函数在页面中使用
1 | <template> |
用法 2:挂载到原型上(类似于 vue3 app.config.globalProperties 挂载全局方法)
1 | // 由于 message modal 这类组件通常用实例生成,我们可以用该形式注册组件 |
1 | <template> |
Nuxt 模块设计
Nuxt3 的模块系统是一个插件化的架构,它允许开发者使用 Nuxt3 构建应用时,以模块的形式来封装和共享各种功能。
Nuxt3 模块系统的设计目录是让开发者能够通过安装和配置模块,快速增加应用程序的功能,而不需要写发咋的代码或进行深度的集成。
- @nuxt/content
- @nuxtjs/auth
- @nuxtjs/i18n
- @nuxtjs/tailwindcss
- @pinia/nuxt
1 | // nuxt.config.ts |
在根目录下创建 store 目录即可,和 pinia 正常用法没啥区别,这里就不贴代码了
这里额外提一下 pinia 持久化,因为刷新页面,数据会初始化
pnpm add pinia-plugin-persistedstate@/nuxt
1 | import { persistedState } from '#imports' |
useState
在 Vue 生态中,我们通常使用 vuex 或是 pinia 来实现状态管理,而在 Nuxt3 中,官方提供了更简洁的 useState 方法,SSR 友好,通过 useState 存储的状态能在 server 和 client 之间共享。
- 使用
需在目录下创建 composables 目录,并在该目录下创建文件,例如:composables/state.ts
useCookie
useCookie 是 Nuxt3 框架中的一个组合 API,用于在客户端和服务端都能访问情况下,使用 useCookit 保存和读取数据(基于开源 cookie 包封装)
使用场景:
- 存储用户信息
- 存储用户偏好,例如语言、主题等
- 存储购物车信息
获取数据
Nuxt3 中的 API 数据获取:
- useFetch
基于 useAsyncData 和 $fetch 封装的。useFetch 将 lazy 参数设置为 true 时,就能实现 useLazyFetch 的效果
useLazyFetch
useAsyncData
useLazyAsyncData
$fetch 全局辅助函数
useFetch 可以实现其他几个 API 的全部功能,实际开发使用 useFetch 即可,其他具体情况具体分析。
在组件中使用$fetch而不使用useAsyncData进行包装会导致数据被获取两次:首先在服务器端获取,然后在客户端进行混合渲染期间再次获取,因为$fetch 不会将状态从服务器传递到客户端。因此,获取将在两端执行,因为客户端需要再次获取数据。
我们建议在获取组件数据时使用 useFetch 或 useAsyncData + $fetch 来防止重复获取数据。