EXIT

00:00:00

打开Nuxt3的大门

[toc]


如何在Nuxt上自由的选择SSR OR SPA :https://www.lichter.io/articles/nuxt3-dynamic-ssr-spa/

配置

Nuxt配置:需要在构建后使用环境变量指定的私有或公共令牌。

nuxt.config.ts:

export default defineNuxtConfig({ // 我的Nuxt配置 })

可配置环境变量与全局变量:

配置:

export default defineNuxtConfig({ runtimeConfig: { // 只在服务器端可用的私有键 apiSecret: '123', // public中的键也可以在客户端使用 public: { apiBase: '/api' } } })

使用方式: 通过**useRuntimeConfig()**组合函数暴露给应用程序的其余部分。

  • 在客户端,只有 runtimeConfig.public 中的键才可用,并且该对象是可写和响应式的。
  • 在服务器端,整个运行时配置都可用于服务器端,但为了避免上下文共享,它是只读的。

nuxt.config.ts 里面的环境变量可以被.env环境变量覆盖.

vite配置:

应用程序配置:可以在应用程序中公开响应式配置,并在运行时通过生命周期或使用nuxt插件进行更新,网站配置(如主题变体、标题)以及不敏感的项目配置.

app.config.ts:

export default defineAppConfig({ //我的应用程序配置; })

使用方式: 通过**useAppConfig()**组合函数暴露给应用程序的其余部分。

路由

页面必须有一个单一的根元素,以允许页面之间的路由过渡,HTML 注释也被视为元素。

跳转方式:

nuxt路由的跳转方式有两种:

  • 编程式导航:navigateTo({path:"...",query:{...}})

页面元数据:

  • 在每一个路由的页面,都可以定义一些路由页面的元数据: 定义:definePageMeta({...}) 使用:const route = useRoute() route.meta 对于非嵌套路由,route.meta只能取到当前页面的元数据,对于嵌套路由,无论父子都可以取到当前嵌套下的所有元数据.

  • 页面元数据有什么用? 可以在进行路由守卫的时候进行鉴权.

  • 特殊元数据:

    • alias:为当前页面设置路由别名,例如:设置别名为"/home",那么原本该路由是/about的,但是现在/home也可以访问到了
    • Keepalive:自动将当前页面包裹在组件中.
    • Layout:可以定义当前页面的布局方式,默认default,但是在此处可以进行更改.
    • layoutTransitionpageTransition:可以为包装页面和布局的transition组件定义过渡属性.
    • Middleware:定义在加载此页面前的中间件.
    • Path:则可以像原先的vue3一样定义原来的路由路径.

路由中间件 Middleware:

路由中间件就是路由导航守卫.

在Nuxt中共有三种路由中间件:

  • **内联middleware:**直接在页面中定义.
  • **命名路由middleware:**放在middleware目录下,并在页面中使用时,通过异步导入的方式导入自动加载.
  • **全局路由middleware:**放在Middleware目录下,以.global结尾,在每次路由更改时运行.

前两种的路由中间件是在definePageMeta中进行定义的: 中间件的名称规范为 kebab-case 格式.

定义方式:

  • 内联定义方式: page/index.ts:

    <script setup lang="ts"> definePageMeta({ middleware:[(to,from)=>{ ... },"other middlewares"] }) </script>
  • middleware目录中定义方式: middleware/my-middleware.ts:

    export default defineNuxtRouteMiddleware((to, from) => { if (to.params.id === '1') { return abortNavigation() } if (to.path !== '/') { return navigateTo('/') } })

中间件不会传递第三个 next 参数,重定向或取消路由由从中间件返回的值处理

Nuxt 提供了两个全局可用的辅助函数,可以直接从中间件中返回。

  • navigateTo:重定向到给定路由.
  • abortNavigation:中止路由继续前进.

整个路由中间件可能得返回值有:

  • 无:继续前进.
  • return navigateTo('/') - 重定向到给定的路径,并在服务器端发生重定向时设置重定向代码为 302;
  • return navigateTo('/', { redirectCode: 301 }) - 重定向到给定的路径,并在服务器端发生重定向设置为 301
  • return abortNavigation() - 停止当前的导航
  • return abortNavigation(error) - 拒绝当前的导航并提供错误信息

中间件的执行顺序是: 全局中间件 -> 页面中定义的中间件的顺序

​ 其中页面中定义的中间件的顺序是指在definePageMeta中,middleware数组中的顺序.

中间件的运行时机:

如果站点是服务器渲染的,初始页面的中间件将在页面呈现时执行,然后在客户端上再次执行。

如果中间件需要浏览器环境,比如生成的站点、缓存响应或从本地存储中读取值,以下设置可能是必须的:

export default defineNuxtRouteMiddleware(to => { // 在服务器端跳过中间件 if (process.server) return // 完全在客户端跳过中间件 if (process.client) return // 或仅在初始客户端加载时跳过中间件 const nuxtApp = useNuxtApp() if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return })

自定义路由:

如果Nuxt3根据目录结构定义的路由方式不符合口味(很难符合),nuxt还提供了自定义路由的方式:

  • 路由配置:使用路由配置,可以覆盖或者拓展路由. app/router.options.ts:

    import type { RouterConfig } from '@nuxt/schema' export default <RouterConfig> { routes: (_routes) => [ { name: 'home', path: '/', component: () => import('~/pages/home.vue').then(r => r.default || r) } ], }
  • Pages钩子:可以使用 pages:extend nuxt 钩子来添加、修改或删除扫描到的路由中的页面。 nuxt.config.ts:

    export default defineNuxtConfig({ ... hooks:{ 'pages:extend'(pages){ //添加一个路由 pages.push({ name: 'profile', path: '/profile', file: '~/extra-pages/profile.vue' }) // 删除路由 function removePagesMatching (pattern: RegExp, pages: NuxtPage[] = []) { const pagesToRemove = [] for (const page of pages) { if (pattern.test(page.file)) { pagesToRemove.push(page) } else { removePagesMatching(pattern, page.children) } } for (const page of pagesToRemove) { pages.splice(pages.indexOf(page), 1) } } removePagesMatching(/\.ts$/, pages); } } })
  • Hash模式:你可以在 SPA 模式下启用哈希历史。在这种模式下,路由器在实际 URL 前使用一个哈希字符(#),该字符在内部传递。启用后,URL 永远不会发送到服务器不支持 SSRnuxt.config.ts:

    export default defineNuxtConfig({ ssr: false, router: { options: { hashMode: true } } })

路由重定向:

Nuxt生命周期钩子

https://nuxt.com.cn/docs/api/advanced/hooks

SEO与Meta

默认设置:在 nuxt.config.ts 文件中提供 app.head 属性,可以自定义整个应用的头部。

nuxt.config.ts:

export default defineNuxtConfig({ app: { head: { charset: 'utf-8', viewport: 'width=device-width, initial-scale=1', } } })

该设置不允许提供响应式数据.如果想使用响应式的头部数据,建议在 app.vue 中使用 useHead()

app.vue:

<script setup lang="ts"> useHead({ title: '我的应用', meta: [ { name: 'description', content: '我的神奇网站。' } ], bodyAttrs: { class: 'test' }, script: [ { innerHTML: 'console.log(\'Hello world\')' } ] }) </script>

当插入具有响应性的标签时,你应该使用计算属性的获取器语法**(() => value):** 和所有组合函数一样,它只能在组件的 setup 和生命周期钩子中使用。

useSeoMeta

useSeoMeta组合函数允许你将站点的SEO元标签定义为一个扁平的对象,并提供完整的TypeScript支持。

这有助于避免拼写错误和常见错误,比如使用 name 而不是 property

app.vue

<script setup lang="ts"> useSeoMeta({ title: '我的神奇网站', ogTitle: '我的神奇网站', description: '这是我的神奇网站,让我来告诉你关于它的一切。', ogDescription: '这是我的神奇网站,让我来告诉你关于它的一切。', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script>

当插入具有响应性的标签时,你应该使用计算属性的获取器语法**(() => value):**

过渡效果

注意 : 必须在SSR状态下过渡效果才会出现.

#设置所有路由的过渡效果:

可以在nuxt.config.ts中设置所有页面的过渡效果:

nuxt.config.ts:

export default defineNuxtConfig({ app: { pageTransition: { name: 'page', mode: 'out-in' } }, })

随后需要再app.vue中进行设置过渡效果的样式才能生效:

app.vue

... <style> .page-enter-active,.page-leave-active { transition: all 0.4s; } .page-enter-from, .page-leave-to { opacity: 0; filter: blur(1rem); } </style>

!需要注意的是:设置全局过渡样式的style一定不能带scoped.

#为不同页设置过渡效果:

在相应的页面的definePageMeta中写入pageTransition{name:...,mode:...}即可.

然后将相应的过渡效果style写到app.vue的style标签中(style不能带scoped),或者对应页面的style标签中(对应页面的style可以是scoped的)即可.

如果有相应的条件限制,也可以写到 middleware 中,通过 to/from中的meta属性获取pageTransition进行设置即可.

#布局的过渡效果:

与设置路由的方法如出一辙,只不过是 pageTransition 变成 layoutTransition.

同理,为不同页面设置不同的布局过渡效果也是一样.

#禁用过渡效果:

全局禁用是 在nuxt.config.ts中 pageTransition / layoutTransition 设置为false.

特定路由禁用则是 只需要在相应的页面 definePageMeta 中对 pageTransition / layoutTransition 设置为false即可禁用.

NuxtPage挂载的过渡效果:

如果是通过点击NuxtPage进行路由跳转,则也可以通过在NuxtPage组件上进行传递transition进行设置过渡效果.

<template> <div> <NuxtLayout> <NuxtPage :transition="{ name: 'bounce', mode: 'out-in' }" /> </NuxtLayout> </div> </template>

!注意: 通过这种方法设置的过渡效果 无法被definePageMeta所覆盖.

数据获取

Nuxt数据获取的方法是useFetchuseAsyncData$fetch => 两个组合函数和一个内置库.

# useFetch的使用方法:

useFetch是一个可组合函数,可以直接在设置函数、插件或路由中调用。它返回响应式的可组合函数,并处理将响应添加到Nuxt的负载中,以便在页面水合时可以从服务器传递给客户端,而无需在客户端重新获取数据。

const { data, pending, error, refresh,sattus } = await useFetch(`https://.....`, config);
  • data:表示得到的数据
  • Pending:表示当前状态
  • Error:表示错误
  • Refresh:表示刷新,再次请求,refresh获得的将只是data.
  • status:表示数据请求的状态的字符串("idle"、"pending"、"success"、"error")。

上述的五种数据都是响应式的.

config是请求的配置项,它包括:

Config : {

  • method:请求方法.
  • query: { param1:'value1', param2: 'value2' } 代表get请求后面?并上的部分.
  • body:请求体.
  • baseURL:请求的基本URL.
  • server:是否在服务端请求数据.
  • lazy:是否在加载路由后解析异步函数,而不是阻止客户端导航.
  • immediate:如果设置为false,将阻止立即发出请求(默认为true),在对应body或query更新时会进行请求。
  • default:一个工厂函数,用于设置data的默认值,在异步函数解析之前使用 - 与lazy: trueimmediate: false选项一起使用。(在未开始请求数据时的默认data.)
  • transform:用来在解析后可以用于更改handler函数结果data函数
  • watch:**是一个数组,数组内是响应式对象.**监听一组响应式源,并在它们发生变化时自动刷新获取的结果。默认情况下,会监听fetch选项和URL。可以通过使用watch: false来完全忽略响应式源。结合immediate: false,可以实现完全手动的useFetch
  • deep:以深层ref对象的形式返回数据(默认为true)。可以设置为false.
  • key:一个唯一的键,用于确保数据获取可以在请求之间正确去重。如果未提供,将根据使用useAsyncData的静态代码位置.
  • headers:设置请求头.
  • responseType:设置响应类型.
  • Pick: ['title'] 只取出响应中的title字段.
  • 一些拦截器:
    • onRequest({request, options}){...}:可以设置请求头等.
    • onRequestError({request, options, error}){...}:处理请求错误.
    • onResponse({ request, response, options }){...}:处理请求数据.
    • onResponseError({ request, response, options }){...}:处理响应错误.

}

所有的fetch选项都可以给定computedref值。如果它们被更新,将自动进行新的请求。

!注意:给定的ref或者computed值进行更新时,不能替换原对象,要在原对象的基础上,更改相应的属性,才能进行新的请求.

# $useAsyncData的使用方法:

事实上,useFetch(url) 几乎等同于 useAsyncData(url, () => $fetch(url)) - 它是为最常见的用例提供的开发者体验糖。

const { data, pending, error, refresh } = await useAsyncData( 'mountains', () => $fetch('https://api.nuxtjs.dev/mountains') )

<<< 为什么使用useAsyncData (什么情况下使用useAsyncData) ? ?

需要自定义封装响应参数或请求函数时,例如,需要等待多个请求响应完成,获取每个响应的结果时:

const { data: discounts, pending } = await useAsyncData('cart-discount', async () => { const [coupons, offers] = await Promise.all([$fetch('/cart/coupons'), $fetch('/cart/offers')]); return { coupons, offers } })

# $fetch:

Nuxt 包括了 ofetch 库,并且作为全局别名 $fetch 自动导入到应用程序中。它是 useFetch 在幕后使用的工具。

const users = await $fetch('/api/users').catch((error) => error.data)

混合渲染

渲染模式:

Nuxt支持不同的渲染模式,包括[通用渲染],[客户端渲染],还提供了[混合渲染]. Nuxt 默认使用通用渲染.

-- 通用渲染:

当浏览器请求启用了通用(服务器端+客户端)渲染的URL时,服务器将一个完整渲染的HTML页面返回给浏览器。无论页面是预先生成并缓存的,还是即时渲染的,在某个时刻,Nuxt都在服务器环境中运行了JavaScript(Vue.js)代码,生成了一个HTML文档。为了不失去客户端渲染方法的好处,如动态界面和页面过渡效果,客户端(浏览器)在下载完HTML文档后会在后台加载运行在服务器上的JavaScript代码。浏览器再次解释它(因此称为通用渲染),Vue.js接管文档并启用交互性。在浏览器中使静态页面具有交互性被称为“水合”。

通用渲染使Nuxt应用程序能够快速加载页面,同时保留了客户端渲染的好处。此外,由于内容已经存在于HTML文档中,爬虫可以在没有额外开销的情况下对其进行索引。

服务器端渲染的好处:

  • 性能:用户可以立即访问页面的内容,因为浏览器可以比JavaScript生成的内容更快地显示静态内容。同时,当水合过程发生时,Nuxt保留了Web应用程序的交互性。
  • 搜索引擎优化:通用渲染将整个HTML内容作为经典服务器应用程序直接传递给浏览器。Web爬虫可以直接索引页面的内容,这使得通用渲染成为任何希望快速索引的内容的绝佳选择。

服务器端渲染的缺点:

  • 成本:为了即时渲染页面,服务器需要运行。这和任何传统服务器一样增加了每月的成本。然而,由于浏览器在客户端导航时接管了服务器调用,调用次数大大减少。

-- 客户端渲染:

传统的Vue.js应用程序默认在浏览器(或客户端)中进行渲染。然后,Vue.js在浏览器下载和解析所有包含创建当前界面指令的JavaScript代码后,生成HTML元素。

客户端渲染的优点:

  • 开发速度:在完全在客户端进行工作时,我们不必担心代码的服务器兼容性,例如,使用仅在浏览器中可用的API,如window对象。
  • 成本较低:运行服务器会增加基础设施成本,因为需要在支持JavaScript的平台上运行。我们可以将仅客户端的应用程序托管在任何具有HTML、CSS和JavaScript文件的静态服务器上。
  • 离线工作:因为代码完全在浏览器中运行,所以在网络不可用的情况下,它可以继续正常工作。

客户端渲染的缺点:

  • 性能:用户必须等待浏览器下载、解析和运行JavaScript文件。根据下载部分的网络和解析和执行的用户设备的性能,这可能需要一些时间,并影响用户的体验。
  • 搜索引擎优化:通过客户端渲染提供的内容进行索引和更新比使用服务器渲染的HTML文档需要更长的时间。这与我们讨论的性能缺点有关,因为搜索引擎爬虫不会等待界面在第一次尝试索引页面时完全渲染。纯客户端渲染将导致内容在搜索结果页面中显示和更新所需的时间更长。

客户端渲染适用于需要大量交互的Web应用程序,不需要索引或其用户频繁访问的应用程序。它可以利用浏览器缓存,在后续访问中跳过下载阶段,例如SaaS、后台应用程序或在线游戏

可以在nuxt.config.ts中启用仅客户端渲染:

nuxt.config.ts:

export default defineNuxtConfig({ ssr: false })

如果使用了ssr: false,你还应该在~/app/spa-loading-template.html中放置一个HTML文件,其中包含你想要用于渲染加载屏幕的HTML。直到应用程序被水合之前,它将被渲染。

-- 混合渲染:

混合渲染允许每个路由使用路由规则的不同缓存规则,并决定服务器如何响应给定URL的新请求。

Nitro有一个强大的功能叫做routeRules,它允许你定义一组规则来自定义Nuxt应用程序的每个路由的渲染方式

nuxt.config.ts:

export default defineNuxtConfig({ routeRules: { // 主页在构建时预渲染 '/': { prerender: true }, // 产品页面按需生成,后台自动重新验证 '/products/**': { swr: 3600 }, // 博客文章按需生成,直到下一次部署前持续有效 '/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: true自动添加CORS头部,你可以通过覆盖headers来自定义输出。
  • headers: object - 为你的站点的某些部分添加特定的头部,例如你的资源文件。
  • swr: number|boolean - 为服务器响应添加缓存头部,并在服务器或反向代理上缓存它,以配置的TTL(存活时间)进行缓存。Nitro的node-server预设能够缓存完整的响应。当TTL过期时,将发送缓存的响应,同时在后台重新生成页面。如果使用true,则添加了一个不带MaxAge的stale-while-revalidate头部。
  • isr: number|boolean - 行为与swr相同,除了我们能够将响应添加到支持此功能的CDN缓存中(目前支持Netlify或Vercel)。如果使用true,内容将在CDN中持久存在,直到下一次部署。
  • prerender:boolean - 在构建时预渲染路由,并将其包含在你的构建中作为静态资源。
  • experimentalNoScripts: boolean - 禁用Nuxt脚本的渲染和JS资源提示,用于你站点的某些部分。

目录结构

https://nuxt.com.cn/docs/guide/directory-structure/nuxt

uid:9nhYrS
VOIDIS.ME
  1. no-like
  2. message
  3. Bilibili
  4. Github
  5. RSS
  6. sun