Nuxt3快速入门

项目初始化

项目创建

 

bash

代码解读

复制代码

npx nuxi init nuxt3-app npm install npm run dev

项目目录结构

 

bash

代码解读

复制代码

nuxt-app/ ├── .nuxt/ #无需关心 ├── .output/ #无需关心 ├── assets/ #静态资源 ├── components/ #公共组件-自动导入 ├── composables/ #公共函数/方法-自动导入 ├── content/ #Nuxt-Content相关-暂无需使用 ├── layouts/ #布局模板 ├── middleware/ #中间件-如路由导航守卫等 ├── node_modules/ #依赖项 ├── pages/ #相应页面-自动添加到路由 ├── plugins/ #插件目录 ├── public/ #静态资源-根目录 └── server/ #用于建立任何后端的逻辑如后端 API,这个目录下还包含了 `api`、`server` 和 `middleware` 来区分功能,不具有自动引入    ├── api/    ├── routes/    └── middleware/ ├── .gitignore ├── .nuxtignore ├── app.config.ts #客户端配置 ├── app.vue #入口组件 ├── nuxt.config.ts #项目配置 ├── package.json └── tsconfig.json #ts配置

路由

页面路由

nuxt3会自动整合vue-router,并且映射pages/目录到应用的routes配置中,既按照pages中的目录文件自动创建相应的路由,如下所示。其中文件夹中index.vue为该路径默认路由组件,而组件/路由的嵌套则和经典的Vue-router类似,不过把router-view以及router-link分别用nuxtPage和nuxtLink进行了替代

 

js

代码解读

复制代码

//文件路径 pages -index.vue -detail --index.vue --some.vue //相应路由 /-index.vue /detail-/detail/index.vue /detail/some-/detail/some.vue

页面组件

 

html

代码解读

复制代码

<template> <div> <NuxtLink to="/test">test</NuxtLink> | <!-- 新增 --> <NuxtLink to="/">根</NuxtLink> <!--新增 --> <NuxtPage></NuxtPage> </div> </template>

动态路由

建立页面文件时,如果命名时将任何内容放在方括号内,它将被转换为路由参数。在文件名或目录中混合和匹配多个参数。

 

text

代码解读

复制代码

-| pages/ ---| index.vue ---| users-[group]/ -----| [id].vue

会生成路由:

 

ts

代码解读

复制代码

{ "routes": [ { "name": "users-group-id", "path": "/users-:group()/:id()", "component": "~/pages/users-[group]/[id].vue" }, ] }

根据上面的例子,你可以通过 $route 对象中的 params 访问组件中的 group & idx

 

html

代码解读

复制代码

<template> <ul class="text-base text-gray-600"> <li> 获取到的 group 是 <span class="text-green-500 text-xl">{{ group }}</span> </li> <li> 获取到的 id 是 <span class="text-green-500 text-xl">{{ id }}</span> </li> </ul> </template>

编程式导航

与 vue3.js 一样,在 setup 可以使用 useRouter、useRoute 来获取路由信息。

 

ts

代码解读

复制代码

<script setup> const route = useRoute(); const router = useRouter(); const { id } = route.params; console.log(router.getRoutes()); const handlerToHome = () => { router.push("/"); }; </script>

自定义路由

配置~/app/router.options.ts

在/src目录新增app文件夹,文件夹下建立router.options.ts文件(如果没有使用本文中的/src目录的配置,要在根目录下新增app文件夹)。该文件返回定制路由的函数来覆盖路由,如果返回 null 或 undefined, Nuxt将退回到默认路由。

 

text

代码解读

复制代码

-| pages/ ---| index.vue

 

ts

代码解读

复制代码

import type { RouterConfig } from "@nuxt/schema"; export default <RouterConfig>{ routes: (_routes) => [ { name: "home", path: "/home", component: () => import("~/pages/index.vue"), }, ], };

访问其他未定义页面路由,比如原本的 /,提示 404;原因是自定义路由完全替换了自动生成的路由。如果我们只是希望在自动导入的路由下,添加自定义路由,应该使用 pages:extend 钩子配置

配置nuxt.config.ts

使用 pages:extend 钩子配置扩展路由

 

ts

代码解读

复制代码

import { NuxtConfig } from "nuxt/config"; import { NuxtPage } from 'nuxt/schema'; export default defineNuxtConfig({ hooks: { 'pages:extend'(pages: NuxtPage[]) { pages.push({ name: 'error', path: '/error', file: '~/error.vue', // 可以传递 props 到业务组件内 props: { error: { statusCode: '500', statusMessage: '服务器开小差啦,请稍后重试', }, }, }); }, }, } as NuxtConfig);

布局Layout

默认布局

那些放在layouts/目录下的SFC会被自动加载进来,如果我们创建的SFC名为default.vue,将会被用于项目所有页面中作为布局模板。

layouts/default.vue:

 

xml

代码解读

复制代码

app.vue <template> <div> hello,nuxt3! <NuxtPage/> <slot /> </div> </template> layout/default.vue <template> <div> 通用布局页,default.vue: <slot /> </div> </template> pages/hello.vue <template> <div> hello page </div> </template>

默认布局会自动嵌套在app.vue中

自定义布局

如果我们的布局文件名不叫default,而是别的,比如custom.vue,想要使用它们,就必须在某个页面中设置页面属性layout

custom.vue:

 

xml

代码解读

复制代码

<template> <div> 内容来自自定义布局页custom.vue! <slot /> </div> </template>

可以在helloworld.vue中试试custom这个布局,helloworld.vue:

 

xml

代码解读

复制代码

<script> export default { layout: "custom" } </script>

NuxtLayout

可以使用NuxtLayout组件结合slots获得完全控制力,同时需要设置组件选项layout: false

helloworld.vue

 

xml

代码解读

复制代码

<template> <NuxtLayout name="custom"> <template #header> <h1>hello page</h1> </template> some content... </NuxtLayout> </template> <script> export default { layout: false, }; </script>

修改一下custom.vue

 

xml

代码解读

复制代码

<template> <div> 内容来自自定义布局页custom.vue! <slot name="header"/> <slot /> </div> </template>

我们甚至能组合多个布局页:

 

xml

代码解读

复制代码

<template> <div> <NuxtLayout name="custom"> <template #header> <h1>hello page</h1> </template> some content... </NuxtLayout> <NuxtLayout name="default"> some content... </NuxtLayout> </div> </template>

由于需要设置layout选项,所以在这个script标签旁边同时使用

 

xml

代码解读

复制代码

<script> export default { layout: "custom", }; </script> <script setup> // your setup script </script>

组件components

自动导入组件

我们把Vue组件放在components/目录,这些组件可以被用在页面和其他组件中,以往我们使用这些组件需要导入并注册它们,但Nuxt会自动导入components/目录中的任意组件。比如:

 

diff

代码解读

复制代码

| components/ --| TheHeader.vue --| TheFooter.vue

layouts/default.vue:

 

xml

代码解读

复制代码

<template> <div> <TheHeader /> <slot /> <TheFooter /> </div> </template>

组件名称约定

没有嵌套的组件会以文件名直接导入,但如果存在嵌套关系哪?例如下面的路径:

 

diff

代码解读

复制代码

| components/ --| base/ ----| foo/ ------| Button.vue

那么组件名称将会基于路径和文件名连起来,比如上面的base/foo/Button.vue注册名称将会是BaseFooButton,将来用起来会像下面这样:

 

xml

代码解读

复制代码

<BaseFooButton />

组件懒加载

如果在组件名前面加上Lazy前缀,则可以按需懒加载该组件,可用于优化打包尺寸。

比如,下面的用法:

 

xml

代码解读

复制代码

<template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true">显示列表</button> </div> </template> <script setup> import {ref} from 'vue' const show = ref(false) </script>

数据获取

nuxt3中提供的数据获取函数有以下四个:

  • useFetch
  • useLazyFetch
  • useAsyncData
  • useLazyAsyncData

注意:它们都必须在setup生命周期钩子中使用

useAsyncData

在页面、组件或插件中都可以使用useAsyncData获取那些异步数据。比如:

 

typescript

代码解读

复制代码

const { data: Ref<DataT>, // 返回的数据 pending: Ref<boolean>, // 加载状态指示器 refresh: (force?: boolean) => Promise<void>, // 强制刷新函数 error?: any // 请求失败的错误信息 } = useAsyncData( key: string,// 唯一键用于多次请求结果去重 fn: () => Object,// 返回数值的异步函数 // lazy - 是否在路由之后才请求数据,server - 是否在服务端请求数据 options?: { lazy: boolean, server: boolean } )

获取待办事项数据,index.vue:

 

xml

代码解读

复制代码

<template> <div> <!-- 待办列表 --> <div v-for="todo in todos" :key="todo.id"> <input type="checkbox" v-model="todo.completed"> <strong>{{todo.title}}</strong> </div> </div> </template> <script setup lang="ts"> const { data: todos } = await useAsyncData( 'count', () => $fetch('/api/todos')) </script>

$fetch使用参考ohmyfetch

useLazyAsyncData

该方法等效于useAsyncData,仅仅设置了lazy选项为true,也就是它不会阻塞路由导航,这意味着我们需要处理data为null的情况(或者给data设置一个默认值)

useFetch

页面、组件或者插件中可以使用useFetch获取任意URL资源。

useFetch是对useAsyncData包装,自动生成key同时推断响应类型,用起来更简单。

看下面方法签名,基本完全相同:

 

typescript

代码解读

复制代码

const { data: Ref<DataT>, pending: Ref<boolean>, refresh: (force?: boolean) => Promise<void>, error?: any } = useFetch(url: string, options?)

useLazyFetch

该方法等效于useFetch,仅设置了lazy选项为true,所以它不会阻塞路由导航,这意味着我们需要处理data为null的情况(或者通过default选购给data设置一个默认值)

最佳实践

只选取需要的数据

由于请求回来的数据会存储在页面payload中,甚至包括那些没有用到的字段,所以文档中明确建议大家只选择那些组件用到的数据,我们可以设置$fetch的pick选项。

比如,下面的用法:

 

ts

代码解读

复制代码

const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] })

状态共享

Nuxt3提供了 useState 创建响应式且服务端友好的跨组件状态共享能力。

useState 是服务端友好的 ref替换。它的值在服务端渲染(客户端注水的过程中)将被保留并通过唯一key在组件间共享。

方法签名
 

js

代码解读

复制代码

useState<T>(key: string, init?: () => T): Ref<T>

  • key:唯一键用于去重
  • init:提供初始值的函数

useState实践

声明一个状态,index.vue

 

javascript

代码解读

复制代码

const counter = useState("counter", () => Math.round(Math.random() * 1000))

 

html

代码解读

复制代码

<button @click="counter++">+</button> {{ counter }} <button @click="counter--">-</button>

共享状态

我们的全局状态当然想要在组件之间共享,此时可以利用nuxt的composables自动导入特性,把它们定义在composables目录中,这样他们将成为全局类型安全的状态。

composables/useCounter.ts

 

javascript

代码解读

复制代码

export const useCounter = () => useState("counter", () => Math.round(Math.random() * 1000));

配置

nuxt3项目中的相关配置主要放在项目根目录下的nuxt.config.ts文件中,除了nuxt3框架需要的配置属性外,你也可以扩展添加自已处理的配置。 默认情况下,配置文件是这样的。

 

arduino

代码解读

复制代码

export default defineNuxtConfig({ // My Nuxt config })

运行时配置

runtimeConfig接口的作用与环境变量类似,在项目中可以使用此接口暴露出来的变量。默认情况下,这些变量只能在服务端使用,但在runtimeConfig.public下的配置也可以在客户端中使用。 这些变量的值需要定义在nuxt.config中,并且可以被环境变量覆盖。 例如:

 

arduino

代码解读

复制代码

export default defineNuxtConfig({ runtimeConfig: { // The private keys which are only available server-side apiSecret: '123', // Keys within public are also exposed client-side public: { apiBase: '/api' } } })

环境变量覆盖

 

ini

代码解读

复制代码

# This will override the value of apiSecret NUXT_API_SECRET=api_secret_token

应用配置

app.config.ts文件默认在项目的根目录下,里头的配置主要是在项目的构建和编译阶段中会使用到。与运行时的配置相反,这里的配置不能被环境变量覆盖。

配置文件中最简单的内容就是导出一个defineAppConfig方法,此方法中有一个你配置对象。

 

php

代码解读

复制代码

// app.config.ts export default defineAppConfig({ title: 'Hello Nuxt', theme: { dark: true, colors: { primary: '#ff0000' } } })

这些变量可以在项目中通过useAppConfig接口来使用.

 

xml

代码解读

复制代码

<script setup> const appConfig = useAppConfig() </script>

runtimeConfigapp.config

这两个的作用都是暴露变量给项目中使用。那在实际项目开发过程中到底使用哪个呢。 runtimeConfig: 项目中需要使用指定的私有和仅有的tokes时 app.config: 可以放一些需要在构建时使用的公共Token, 例如主题变量,标题等不敏感的数据

env配置

.env的变量会打入到process.env中,符合规则的会覆盖runtimeConfig的变量 默认加载 .env 文件的配置

.env 文件内容

 

ini

代码解读

复制代码

NUXT_PUBLIC_API_BASE=http://127.0.0.1:53105/mk

.env.production 文件内容

 

bash

代码解读

复制代码

NUXT_PUBLIC_API_BASE=https://vaebe.top:53104/mk

也许你发现了 NUXT_PUBLIC_API_BASE 这个变量, 看下上边的 设置环境变量 就会发现其实就是把对象字段 key 进行拼接。

所以 API_BASE 对应的就是 runtimeConfig\public 配置里的 apiBase 这个字段,.env 文件的变量应该与 runtimeConfig 配置的内容相同。

如果不在 public 下那就应该是 NUXT_API_BASE=xxxxxxx

渲染模式

Nuxt支持不同的渲染模式

  • 通用渲染
  • 客户端渲染
  • 混合渲染
  • CDN边缘服务器上渲染

通用渲染

通用渲染模式是服务器端+客户端一起使用的。服务器会首先向浏览器返回一个完整的HTML,这个HTML可能是构建的时候预渲染,也有可能是执行的时候再渲染出来的。这就是服务端渲染的步骤

然后为了不失去客户端渲染的优势,例如动态界面和页面过度,客户端再下载这个HTML之后,还会在后台加载原本在Server上运行的js代码。浏览器会再次解释调用它

这回使得这个静态页面,重新拥有了动态能力。这个过程叫做Hydration,水合作用

服务端渲染的好处

  • 性能:用户一下子就能获得完整的内容,响应更加快了
  • SEO: 搜索引擎一般只能爬取HTML,不会执行js。所以你的内容更加容易呈现给搜索引擎

服务端渲染的缺点

  • 开发麻烦,需要考虑不同环境下的api
  • 成本,服务器的成本增加了

客户端渲染

就像是传统的Vue项目一样。打包出来的html会执行main.js。这包含完整的Vue.js代码,然后开始解析用户的操作

好处:

  • 开发速度,更快了,而且只有一套浏览器的api
  • 便宜,运行成本转嫁给用户了
  • 离线,它允许用户下载完完整的代码后,离线运行一时间

缺点

  • 性能,用户要等待下载、解析和运行js文件
  • SEO不好,同上

Nuxt也提供这种方式

 

ts

代码解读

复制代码

export default defineNuxtConfig({ ssr: false })

部署一个静态的客户端渲染的应用程序

如果你使用 nuxi generatenuxi build --prerender 命令将应用部署到静态托管服务上,那么默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。

如果你只使用客户端渲染,这可能是没有必要的。你只需一个index.html 文件,再加上 200.html404.html 的回退页面,你可以告诉你的静态网页托管服务对所有请求提供这些文件。 为了实现这一点,我们可以改变路由的预渲染方式。只需在你的 nuxt.config.ts 文件中的 hooks 添加以下内容:

 

ts

代码解读

复制代码

export default defineNuxtConfig({ hooks: { 'prerender:routes' ({ routes }) { routes.clear() // Do not generate any routes (except the defaults) } }, })

然后,Nuxt只生成三个文件

  • index.html
  • 200.html
  • 404.html

混合渲染

如果你想有的部分使用通用渲染,有部分使用客户端渲染。也是可以的

例如一个CMS管理系统。一些向外展示的页面应该是静态的,但是管理后台需要注册功能,更像一个动态应用。

Nuxt支持在路由规则中设置渲染模式,以支持混合渲染。

 

ts

代码解读

复制代码

export default defineNuxtConfig({ routeRules: { // 构建的时候就进行预渲染 '/': { prerender: true }, // 产品页面按需生成,在后台重新验证,缓存直到API响应更改 '/products': { swr: true }, // 产品页面按需生成,后台重新验证,缓存1小时(3600秒) '/products/**': { swr: 3600 }, // 博客文章页面按需生成,在后台重新验证,在CDN上缓存1小时(3600秒) '/blog': { isr: 3600 }, // 博客文章页面按需生成一次,直到下一次部署,缓存在CDN上 '/blog/**': { isr: true }, // 管理仪表板只在客户端渲染 '/admin/**': { ssr: false }, // 在API路由中添加cors头 '/api/**': { cors: true }, // 重定向遗留url '/old-page': { redirect: '/new-page' } } })

路由规则

你可以使用的不同属性如下:

  • redirect: string — 定义服务器端重定向。
  • ssr: boolean — 对应用程序的部分区域禁用服务器端渲染,并将其设置为仅单页应用(SPA)模式,通过设置 ssr: false 实现。
  • cors: boolean — 自动添加跨源资源共享(CORS)头部,通过设置 cors: true 实现。可以通过覆盖 headers 属性来定制输出。
  • headers: 对象 — 向网站的特定部分添加特定的头部信息——例如,你的资源文件。
  • swr: 数字或布尔值 — 向服务器响应添加缓存头部,并在服务器或反向代理上为可配置的存活时间(TTL)缓存该响应。Nitro 的 Node 服务器预设能够缓存完整的响应。当 TTL 到期后,会发送已缓存的响应,同时在后台重新生成页面。如果使用 true,则会添加一个无过期时间的验证缓存(stale-while-revalidate)头部,但不指定最大有效期(MaxAge)。
  • isr: 数字或布尔值 — 其行为与 swr 相同,只是我们能够在支持此功能的平台(目前为 Netlify 或 Vercel)上将响应添加到内容分发网络(CDN)缓存中。如果使用 true,则内容会在 CDN 中保留到下一次部署。
  • prerender: 布尔值 — 在构建时预先渲染路由,并将它们作为静态资源包含在构建中。
  • experimentalNoScripts: 布尔值 — 对网站的部分区域禁用 Nuxt 脚本和 JavaScript 资源提示的渲染。
  • appMiddleware: 字符串、字符串数组或记录类型(键为字符串,值为布尔值)——允许你定义应该或不应该在 Vue 应用程序部分(即,非 Nitro 路由)的页面路径中运行的中间件。

边缘渲染

这是一个Nuxt引入的强大的功能,它使得Nuxt像静态网站一样支持CDN分发。

边缘侧渲染的工作原理是将渲染过程推送到网络的“边缘”位置,即 CDN 的边缘服务器。需要注意的是,ESR 更多是一种部署目标而非实际的渲染模式。

当请求某个页面时,请求不会直接到达原始服务器,而是被最近的边缘服务器截获。这个服务器会生成页面的 HTML 并将其发送回用户。这一过程减少了数据传输的实际距离,降低了延迟,并加快了页面加载速度

边缘侧渲染得以实现要归功于 Nitro,这是为 Nuxt 3 提供动力的服务器引擎。Nitro 支持跨平台,包括 Node.js、Deno、Cloudflare Workers 等。

目前可以利用边缘侧渲染的平台有:

  • 使用 Git 集成和 nuxt build 命令,在 Cloudflare Pages 上无需任何配置即可实现边缘侧渲染。
  • 使用 nuxt build 命令和环境变量 NITRO_PRESET=vercel-edge 在 Vercel 边缘函数上启用边缘侧渲染。
  • 使用 nuxt build 命令和环境变量 NITRO_PRESET=netlify-edge 在 Netlify 边缘函数上启用边缘侧渲染。

值得注意的是,当你使用边缘侧渲染结合路由规则时,可以使用混合渲染(Hybrid Rendering)。

原文链接:https://juejin.cn/post/7419894731813912586

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值