nuxt3:我们开始吧!
创始人
2024-02-25 00:39:09
0

一、背景介绍

2022 年 11 月 16 日,全球最大的 Nuxt 会议 Nuxt Nation 2022 在线举行,并正式发布了 Nuxt.js 3.0 的第一个稳定版本。Nuxt 3 是基于 ViteVue3 和 Nitro 的 Nuxt 框架的现代重写,具有一流的 Typescript 支持,是两年多研究、社区反馈、创新和实验的结果。为每个人提供了一个愉快的 Vue 全栈开发体验。

因为nuxt优越的服务端渲染能力,所以对于nuxt3项目关注已久!我们开始吧!

二、官方网址

Nuxt 3 - 中文文档

Nuxt - The Intuitive Vue Framework

Announcing 3.0 · Nuxt

Nuxt - Installation

https://github.com/nuxt/create-nuxt-app/blob/master/README.md

三、新特性介绍

1、更轻量:以现代浏览器为目标的服务器部署和客户端产物最多可缩小 75 倍
2、更快:基于 nitro 提供动态代码分割能力,以优化冷启动性能
3、Hybrid:增量静态生成和其他的高级功能现在都成为可能
4、Suspense:在任意组件和导航前后都可以获取数据
5、Composition API:使用 Composition API 和 Nuxt 3 的 composables 实现真正的代码复用
6、Nuxt CLI:没有任何依赖,帮你轻松搭建项目和集成模块
7、Nuxt Devtools:通过直接在浏览器中查看信息和快速修复实现更快地工作
8、Nuxt Kit:具有 Typescript 和跨版本兼容性的全新模块开发
9、Webpack 5:更快的构建时间和更小的包大小,无需配置
10、Vite:使用 Vite 作为打包工具,体验闪电般快速的 HMR
11、Vue 3:Vue 3 是你下一个 Web 应用程序的坚实基础
12、TypeScript:使用原生 TypeScript 和 ESM 构建,无需额外步骤

Nuxt 3.0 稳定版正式发布,基于 Vue 3 的 Web 框架

四、重要概念

SPA应用:也就是单页应用,这些多是在客户端的应用,不能进行SEO优化(搜索引擎优化)。

SSR应用:在服务端进行渲染,渲染完成后返回给客户端,每个页面有独立的URL,对SEO友好。

约定式路由:不需要配置路由,在根目录pages目录下创建业务页面,即可访问。

约定式配置:如layouts布局、middleware、plugins

五、启动基础项目

https://github.com/nuxt/create-nuxt-app/blob/master/README.md

5.1、创建项目:

创建nuxt3项目:

pnpm dlx nuxi init nuxt-app

 npx nuxi init nuxt3-app

5.2、安装依赖

pnpm install --shamefully-hoist

5.3、启动项目

启动成功

六、项目配置、基础使用

6.1、访问pages/index.vue

根目录app.vue,替换为:


pages/index.vue

pages/about.vue  

这样就可以访问页面了:

6.2、动态路由

6.2.1、目录结构

6.2.2、访问:/user

如果没有pages/user/index页面,只有[id].vue,访问的时候式404页面

6.2.3、访问:/user/1,动态路由,获取动态路由参数

{{$route.params.id}}

6.2.4、访问:/user/1?name=snow,动态路由,获取路由普通参数:

{{$route.query.name}}

 6.2.5、通过useRoute()获取路由信息

const route = useRoute()

6.3、路由跳转

经过测试一下几种方式均成功跳转。页面内容均正常展示。

6.3.1、

user-id

6.3.2、 

user-id-2

6.3.3、

user-id-3

6.3.4、编程式路由

6.4、加载静态资源

 nuxt项目tsconfig.json有配置,public目录下的文件可以省略/public目录,我这里测试不可以,后续会再研究

6.5、设置页面title,不会在页面展示,只会在页面title部分展示

6.5.1、

snow-title

如图:

 ctrl + u:

 6.5.2、使用useHead()方法

useHead({title: 'snow-title-2'
})

设置成功,useHead优先级小于标签。</p> <p>6.5.3、同理使用useHead设置页面的TDK信息</p> <pre><code><script setup lang="ts"> useHead({title: 'snow-title-2',meta: [{ name: 'description', content: 'snow-desc'},{ name: 'keywords', content: 'snow-kw'}] }) </script></code></pre> <p><img alt="" height="227" src="https://img.pic99.top/hhfamen/202402/91c27d3f4d322bf.png" width="977" /></p> <p></p> <p><strong>6.6、layouts</strong></p> <p>6.6.1、理解:布局、页面布局、公共布局、基础布局</p> <p>6.6.2、根目录创建layouts目录,/layouts/default.vue</p> <pre><code><template><div>snow-default-layout</div><slot /> </template><script setup lang="ts"></script><style scoped></style> </code></pre> <p>6.6.3、app.vue</p> <pre><code><template><NuxtLayout><NuxtPage/></NuxtLayout><!-- <div><NuxtWelcome /></div> --> </template> </code></pre> <p><img alt="" height="533" src="https://img.pic99.top/hhfamen/202402/d793c0f8a488aa2.png" width="991" /></p> <p> 6.6.4、</p> <p><img alt="" height="265" src="https://img.pic99.top/hhfamen/202402/53f1d8c74352688.png" width="648" /></p> <p> 6.6.5、某页面不想使用layout:</p> <pre><code>definePageMeta({layout: false })</code></pre> <p>6.6.6、某页面使用指定layout</p> <p><img alt="" height="151" src="https://img.pic99.top/hhfamen/202402/cfa99752659880e.png" width="345" /></p> <pre><code>definePageMeta({layout: 'layout-snow' })</code></pre> <p>  6.6.7、动态设置layout</p> <pre><code>const router = useRoute() function enableLayout () {router.meta.layout = "layout-snow" }</code></pre> <p>6.6.8、全局设置,指定layout</p> <pre><code class="hljs"><template><NuxtLayout :name="layoutSnow"><NuxtPage/></NuxtLayout><!-- <div><NuxtWelcome /></div> --> </template> <script setup lang="ts"> const layoutSnow = ref("layout-snow") </script></code></pre> <p><strong>6.7、plugins</strong></p> <p>/plugins/index.ts</p> <pre><code class="hljs">export default defineNuxtPlugin(()=>{return {provide: {hello: (msg: string) => `hello ${msg}`}} })</code></pre> <p>/pages/plugin.vue</p> <pre><code class="hljs"><template><div>snow-plugin</div> </template><script setup lang="ts"> const { $hello } = useNuxtApp() console.log('9', $hello('world')) </script><style scoped> </style> </code></pre> <p><img alt="" height="505" src="https://img.pic99.top/hhfamen/202402/57f42eae40d00bc.png" width="958" /></p> <p><strong>6.8、middleware</strong></p> <p>/middleware/auth.ts</p> <pre><code class="hljs">export default defineNuxtRouteMiddleware((to, from)=>{console.log("auth") }) </code></pre> <p>/middleware/snow.ts</p> <pre><code class="hljs">export default defineNuxtRouteMiddleware((to, from)=>{console.log("snow") }) </code></pre> <p>/pages/plugin.vue</p> <pre><code class="hljs"><template><div>snow-plugin</div> </template><script setup lang="ts">definePageMeta({middleware: ["auth", "snow"] })</script><style scoped> </style> </code></pre> <p> 如图:</p> <p><img alt="" height="544" src="https://img.pic99.top/hhfamen/202402/fe8766b5e938.png" width="910" /></p> <p>6.9、封装接口请求</p> <p>待补充</p> <p>6.10、多环境开发</p> <p>待补充</p> <p>6.11、其他内容</p> <p>待补充</p> <p><strong>七、过程记录</strong></p> <p>7.1、init项目不成功</p> <p><img alt="" height="229" src="https://img.pic99.top/hhfamen/202402/3f3fe2371711813.png" width="759" />解:墙内的同学可能创建不成功,这里推荐一个链接:https://github.com/nuxt/starter</p> <p>7.2、useHead接收参数如下:</p> <pre><code>useHead(meta: Computable<MetaObject>): voidinterface MetaObject extends Record<string, any> {charset?: stringviewport?: stringmeta?: Array<Record<string, any>>link?: Array<Record<string, any>>style?: Array<Record<string, any>>script?: Array<Record<string, any>>noscript?: Array<Record<string, any>>titleTemplate?: string | ((title: string) => string)title?: stringbodyAttrs?: Record<string, any>htmlAttrs?: Record<string, any> }</code></pre> <pre><code>charset: 指定 HTML 的字元编码,预设为 utf-8。 viewport: 设定网页的可见区域,预设为 width=device-width, initial-scale=1。 meta: 接受一个阵列,阵列中的每个元素,都將会建立一个 <meta> 标记,元素中物件的属性将对应至的属性。 link: 接受一个阵列,阵列中的每个元素,都将会建立一个 <link> 标记,元素中物件的属性将对应至的属性。 style: 接受一个阵列,阵列中的每個元素,都将会建立一个 <style> 标记,元素中物件的属性将对应至的属性。 script: 接受一个阵列,阵列中的每個元素,都将会建立一个 <script> 标记,元素中物件的属性将对应至的属性。 noscript: 接受一个阵列,阵列中的每個元素,都将会建立一个 <noscript> 标记,元素中物件的属性将对应至的属性。 titleTemplage: 接受一個字串或函數,用來动态的设定该页面元件的网页标题。 title: 在页面元件设置静态的网页标题。 bodyAttrs: 接受一个物件,设置网页中标识的属性,物件中的属性将对应至的属性。 htmlAttrs: 接受一个物件,设置网页中标识的属性,物件中的属性将对应至的属性。</code></pre> <p>理解useHead:相当于设置页面<head>标签内相关内容。</p> <p></p> <p><strong>八、欢迎交流指正,关注我,一起学习。</strong></p> <p><img alt="" height="425" src="https://img.pic99.top/hhfamen/202402/1db1ac31d135f7f.png" width="859" /></p> <p> </p> <p><strong>参考链接:</strong></p> <p>[Day 24] Nuxt 3 搜尋引擎最佳化 (SEO) 與 HTML Meta Tag - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天</p> <p>Nuxt3-动态更改meta信息(关键词、标题、描述)_fat_shady的博客-CSDN博客</p> <p>令人愉快的 Nuxt3 教程 (一): 应用的创建与配置 - 知乎</p> <p>技术胖-Nuxt3从零到实战手把手 免费视频图文教程</p> <p>Nuxt.js 3.0 正式发布! - 知乎</p> <p></p> <!--end::Text--> </div> <!--end::Description--> <div class="mt-5"> <!--关键词搜索--> </div> <div class="mt-5"> <p class="fc-show-prev-next"> <strong>上一篇:</strong><a href="/keji/4188.html">一些计算机的冷知识,你都知道吗?</a><br> </p> <p class="fc-show-prev-next"> <strong>下一篇:</strong><a href="/keji/4193.html">python 高级技巧</a> </p> </div> <!--begin::Block--> <div class="d-flex flex-stack mb-2 mt-10"> <!--begin::Title--> <h3 class="text-dark fs-5 fw-bold text-gray-800">相关内容</h3> <!--end::Title--> </div> <div class="separator separator-dashed mb-9"></div> <!--end::Block--> <div class="row g-10"> </div> </div> <!--end::Table widget 14--> </div> <!--end::Col--> <!--begin::Col--> <div class="col-xl-4 mt-0"> <!--begin::Chart Widget 35--> <div class="card card-flush h-md-100"> <!--begin::Header--> <div class="card-header pt-5 "> <!--begin::Title--> <h3 class="card-title align-items-start flex-column"> <!--begin::Statistics--> <div class="d-flex align-items-center mb-2"> <!--begin::Currency--> <span class="fs-5 fw-bold text-gray-800 ">热门资讯</span> <!--end::Currency--> </div> <!--end::Statistics--> </h3> <!--end::Title--> </div> <!--end::Header--> <!--begin::Body--> <div class="card-body pt-3"> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202406/78b0249c98149a3.jpeg')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/33665.html" class="text-dark fw-bold text-hover-primary fs-6">监控摄像头接入GB28181平...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202402/b7fd57091ce17d7.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/952.html" class="text-dark fw-bold text-hover-primary fs-6">Windows10添加群晖磁盘...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202406/793e3f6ce04ed0b.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/33802.html" class="text-dark fw-bold text-hover-primary fs-6">protocol buffer...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202406/635b8ed7ba7c4e2.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/33708.html" class="text-dark fw-bold text-hover-primary fs-6">Fluent中创建监测点</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202405/9a5663f39d0d86.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/26657.html" class="text-dark fw-bold text-hover-primary fs-6">educoder数据结构与算法...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">                                                  ...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202403/50b5d39a4edb96e.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/14338.html" class="text-dark fw-bold text-hover-primary fs-6">MySQL下载和安装(Wind...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202403/9079391fc319.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/9298.html" class="text-dark fw-bold text-hover-primary fs-6">MFC文件操作</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7"> MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202403/98c3f25f21a67b3.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/7709.html" class="text-dark fw-bold text-hover-primary fs-6">在Word、WPS中插入AxM...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/33745.html" class="text-dark fw-bold text-hover-primary fs-6">有效的括号</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">一、题目 给定一个只包括 '(',')','{','}'...</span> </div> <!--end::Title--> </div> <!--begin::Item--> <div class="d-flex flex-stack mb-7"> <!--begin::Symbol--> <div class="symbol symbol-60px symbol-2by3 me-4"> <div class="symbol-label" style="background-image: url('https://img.pic99.top/hhfamen/202404/0a28a5fa0a16d86.png')"></div> </div> <!--end::Symbol--> <!--begin::Title--> <div class="m-0"> <a href="/keji/25416.html" class="text-dark fw-bold text-hover-primary fs-6">【Ctfer训练计划】——(三...</a> <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...</span> </div> <!--end::Title--> </div> </div> <!--end::Body--> </div> <!--end::Chart Widget 35--> </div> <!--end::Col--> </div> </div> <!--end::Content container--> </div> <!--end::Content--> </div> <!--end::Content wrapper--> <!--begin::Footer--> <div id="kt_app_footer" class="app-footer"> <!--begin::Footer container--> <div class="app-container container-xxl d-flex flex-column flex-md-row flex-center flex-md-stack py-3"> <!--begin::Copyright--> <div class="text-dark order-2 order-md-1"> <span class="text-muted fw-semibold me-1">2025 ©</span> <a href="/" target="_blank" class="text-gray-800 text-hover-primary">发门网</a> <a href="https://beian.miit.gov.cn/" target="_blank" class="text-gray-800 text-hover-primary"></a> <a href="http://www.bitekongjian.com">比特空间</a><a href="http://www.zzszq.net">深知网</a><a href="http://www.hysmm.com/">行业商贸网</a><a href="http://www.981608.com/">一路旅游网</a> </div> <!--end::Copyright--> <!--begin::Menu--> <ul class="menu menu-gray-600 menu-hover-primary fw-semibold order-1"> <li class="menu-item"> <a href="/news/" target="_blank" class="menu-link px-2">资讯</a> </li> <li class="menu-item"> <a href="/shenghuo/" target="_blank" class="menu-link px-2">生活</a> </li> <li class="menu-item"> <a href="/keji/" target="_blank" class="menu-link px-2">科技</a> </li> <li class="menu-item"> <a href="/sitemap.xml" target="_blank" class="menu-link px-2">sitemap</a> </li> </ul> <!--end::Menu--> </div> <!--end::Footer container--> </div> <!--end::Footer--> </div> <!--end:::Main--> </div> <!--end::Wrapper--> </div> <!--end::Page--> </div> <!--end::App--> <div id="kt_scrolltop" class="scrolltop" data-kt-scrolltop="true"> <!--begin::Svg Icon | path: icons/duotune/arrows/arr066.svg--> <span class="svg-icon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <rect opacity="0.5" x="13" y="6" width="13" height="2" rx="1" transform="rotate(90 13 6)" fill="currentColor"></rect> <path d="M12.5657 8.56569L16.75 12.75C17.1642 13.1642 17.8358 13.1642 18.25 12.75C18.6642 12.3358 18.6642 11.6642 18.25 11.25L12.7071 5.70711C12.3166 5.31658 11.6834 5.31658 11.2929 5.70711L5.75 11.25C5.33579 11.6642 5.33579 12.3358 5.75 12.75C6.16421 13.1642 6.83579 13.1642 7.25 12.75L11.4343 8.56569C11.7467 8.25327 12.2533 8.25327 12.5657 8.56569Z" fill="currentColor"></path> </svg> </span> <!--end::Svg Icon--> </div> <!--begin::Javascript--> <script>var hostUrl = "/static/default/pc/";</script> <!--begin::Global Javascript Bundle(mandatory for all pages)--> <script src="/static/default/pc/plugins/global/plugins.bundle.js"></script> <script src="/static/default/pc/js/scripts.bundle.js"></script> <!--end::Global Javascript Bundle--> <!--end::Javascript--> </body> <!--end::Body--> </html>