Nuxt 3组件开发与管理
扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长
第1章:Nuxt 3简介
1.1 Nuxt 3概述
1.1.1 什么是Nuxt.js Nuxt.js是一个基于Vue.js的开源框架,专为构建高性能、可维护的服务器渲染和静态站点生成应用而设计。Nuxt 3是其最新版本,它采用Vue 3和TSX(TypeScript的扩展)作为基础,提供了更简洁的API和更好的性能。
1.1.2 Nuxt 3特点
- 服务器端渲染(SSR):提高SEO和初始加载速度。
- 前端应用(SPA):现代的单页应用体验。
- 静态站点生成(SSG):支持快速的静态内容部署。
- 集成强大:与Vue生态系统无缝集成,如Vuex、Vuex-ORM等。
1.2 安装与配置
1.2.1 安装Nuxt 3 在命令行中运行以下命令安装Nuxt 3 CLI:
1 | npm install -g npx |
或者使用Yarn:
1 | yarn global add create-nuxt-app |
1.2.2 配置基本项目
- 进入项目目录:
cd my-app
- 配置
nuxt.config.ts
:设置基础配置,如目标环境、SSR、SSG等。
1 | // nuxt.config.ts |
1.3 基本架构介绍
1.3.1 项目结构
pages
:存放所有路由相关的组件,如pages/index.vue
。components
:存放可复用的Vue组件。layouts
:定义页面布局,如layouts/default.vue
。plugins
:全局或局部插件。store
:Vuex状态管理。
1.3.2 主要组件类型
- Layouts: 共享的页面结构,如头部、尾部和主要内容区域。
- Pages: 与特定路由关联的组件,处理业务逻辑和视图。
- Modules: 对项目进行分模块管理,如API、状态管理等。
1.3.3 CLI命令
nuxt generate
:生成静态站点。nuxt start
:启动开发服务器。nuxt build
:构建生产环境。
第2章:Nuxt 3组件基础
2.1 组件定义与分类
2.1.1 组件定义 在Nuxt 3中,组件是可复用的代码块,可以是Vue组件或自定义的函数式组件。Vue组件使用.vue
文件扩展名,而函数式组件使用<script setup>
语法。
2.1.2 组件分类
- 独立组件(Single File Components, SFC):如
.vue
文件,包含模板、逻辑和样式。 - 函数式组件(Functional Components):使用
<script setup>
,更简洁,侧重于逻辑和数据处理。 - 组件库:预编译的组件集合,可以自定义或使用第三方库。
2.2 简单组件示例
2.2.1 独立组件示例
1 | <!-- pages/components/Button.vue --> |
2.2.2 函数式组件示例
1 | <!-- pages/components/Button.vue --> |
2.3 Props和Slots的使用
2.3.1 Props(属性)
- Props是组件间的通信方式,父组件向子组件传递数据。
props
对象定义组件接受的属性,如上述按钮组件的buttonText
和isActive
。
2.3.2 Slots(插槽)
- Slots用于在组件中定义可替换的部分,父组件可以通过
<slot>
标签传递内容给子组件。 - 子组件可以使用
<template v-slot>
来定义默认插槽或命名插槽。
2.4 使用Composition API
2.4.1 Refs(响应式引用)
- Composition API引入了
ref
,用于创建响应式的变量,如上述isActive
和buttonText
。
2.4.2 Setup Function(设置函数)
setup
函数是组件的逻辑核心,替代了.vue
文件中的export default
部分,用于导入和导出函数、变量和方法。
1 | <script setup> |
第3章:组件开发实践
3.1 自定义组件开发
3.1.1 组件结构
在Nuxt 3中,自定义组件通常包含<template>
、<script setup>
和<style>
部分。
<template>
:定义组件的视图结构,包括HTML结构和模板指令。<script setup>
:定义组件的逻辑,包括数据、计算属性、方法、生命周期钩子等。<style>
:定义组件的样式,可以使用CSS、SCSS、LESS等。
例如,创建一个名为MyComponent.vue
的自定义组件:
1 | <template> |
3.1.2 组件实例
每个组件都有一个实例,可以通过this
关键字访问组件内部的变量和方法。
在<script setup>
中,可以使用defineProps
、defineEmits
、defineExpose
等API来定义属性和方法。
例如,在上面的MyComponent.vue
中,可以使用defineProps
来定义title
属性:
1 | <script setup> |
在父组件中,可以使用v-bind
来传递title
属性:
1 | <template> |
3.2 异步加载组件
在 Nuxt 3 中,可以使用异步加载来延迟加载组件,从而提高应用程序的性能和用户体验。
3.2.1 动态导入
可以使用动态导入来异步加载组件。在<script setup>
中,可以使用import
关键字来动态导入组件:
1 | <template> |
在上面的例子中,AsyncComponent
是一个动态导入的组件,只有在点击按钮时才会加载。
3.2.2 异步数据
如果组件需要加载异步数据,可以在<script setup>
中使用async/await
来加载数据,并在数据加载完成后渲染组件。
例如,在下面的例子中,AsyncDataComponent
组件需要加载一个异步数据:
1 | <template> |
在上面的例子中,点击按钮时会调用loadData
方法,加载异步数据,并在数据加载完成后渲染AsyncDataComponent
组件。
3.3 事件与方法
方法(Methods)
在 Nuxt 3 中,组件内的方法是通过在 <script setup>
或 <script>
标签中定义 methods
对象来实现的。这些方法可以在模板中被调用,也可以在组件内部的其他方法中被调用。
以下是一个简单的示例:
1 | <template> |
在这个例子中,increment
方法会在点击按钮时被调用,使得 count
的值增加。
事件(Events)
自定义事件
组件可以通过 $emit
方法发出自定义事件,父组件可以通过监听这些事件来响应。
以下是如何在子组件中发出一个自定义事件的示例:
1 | <template> |
父组件可以像这样监听这个事件:
1 | <template> |
原生事件
你还可以在组件上直接监听原生 DOM 事件,如下所示:
1 | <template> |
使用 Vuex 中的事件和方法
如果在使用 Vuex 来管理状态,你可能会在组件中调用 Vuex 的 actions
或 mutations
。
1 | <template> |
在这个例子中,当按钮被点击时,会调用 Vuex store 中的 increment
action。
第4章:组件组织与管理
4.1 组件目录结构
在 Nuxt.js 3.x 中,组件目录结构非常灵活,你可以根据项目需求自定义组件的存放位置。但是,为了保持代码结构的清晰和可维护,建议按照以下目录结构组织组件:
通用组件:将所有可复用的组件放在
components
目录中。例如:1
2
3
4
5components/
- Button.vue
- Input.vue
- Icon.vue页面组件:每个页面组件都可以作为一个单独的
.vue
文件存在,并放在pages
目录中。例如:1
2
3
4
5
6
7pages/
- index.vue
- about.vue
- products/
- index.vue
- product-1.vue布局组件:布局组件可以放在
layouts
目录中。例如:1
2
3
4layouts/
- default.vue
- admin.vue插件:如果你需要在组件中使用第三方库或自定义插件,可以将它们放在
plugins
目录中。例如:1
2
3
4plugins/
- third-party.js
- custom.js模块:如果你需要在项目中使用自定义模块,可以将它们放在
modules
目录中。例如:1
2modules/
- custom-module.js
4.2 分级组件和模块化
在 Nuxt 3 中,组件化和模块化是两个核心概念,它们有助于构建可维护和可扩展的应用程序。以下是关于 Nuxt 3 中的分级组件和模块化的详细说明:
分级组件(Hierarchical Components)
分级组件指的是组件之间的嵌套关系,这种关系可以帮助我们构建复杂的用户界面。在 Nuxt 3 中,组件可以按照以下方式组织:
- 根组件:通常位于
pages
目录下的.vue
文件,它们是页面的入口。 - 子组件:可以在页面组件中或其它组件中嵌套使用的组件。子组件通常放在
components
目录下,并可以进一步细分为子目录,以反映它们的功能或用途。
以下是一个分级组件的例子:
1 | components/ |
在这个结构中,Header
和 Footer
目录包含了与它们相关的子组件,而 Hero
和 ArticleList
是独立的组件。
模块化(Modularization)
模块化是一种将代码分解成可重用模块的方法,每个模块都专注于一个特定的功能。在 Nuxt 3 中,模块化可以通过以下方式实现:
- Nuxt 模块:Nuxt 3 支持通过
modules
目录或nuxt.config.ts
文件自动注册本地或第三方模块。这些模块可以扩展 Nuxt 的核心功能或提供额外的工具。 - 可复用逻辑:将可复用的逻辑(如 API 调用、状态管理、工具函数)放在单独的文件或目录中,然后在需要的地方导入它们。
以下是一个模块化的例子:
1 | composables/ |
在这个结构中,composables
目录包含了可复用的组合式函数,store
目录包含了状态管理逻辑,而 utils
目录包含了工具函数和验证器。
结合分级组件和模块化
在 Nuxt 3 中,你可以将分级组件和模块化结合起来,创建一个既清晰又易于维护的项目结构:
- 使用分级组件来组织你的用户界面。
- 使用模块化来组织你的应用逻辑。
通过这种方式,你可以确保每个组件都专注于展示逻辑,而模块则处理应用的业务逻辑,从而实现关注点分离。例如:
1 | components/ |
在这个结构中,Header
和 Footer
组件可以导入对应的 useHeader
和 useFooter
组合式函数来获取所需的数据和逻辑。这样的组织方式有助于保持代码的清晰和可维护性。
4.3 使用Layouts和Modules
Nuxt 3 中的 Layouts 和 Modules 是两个重要的概念,它们可以帮助你构建更加灵活和可扩展的应用程序。以下是关于 Nuxt 3 中的 Layouts 和 Modules 的详细说明:
Layouts
Layouts 是一种在 Nuxt 中定义应用程序布局的方式,它们可以让你在不同页面之间共享相同的布局。在 Nuxt 3 中,你可以在 layouts
目录中创建自定义的布局。
以下是一个简单的 Layouts 示例:
创建一个名为
layouts
的目录,并在其中创建一个名为default.vue
的文件:1
2
3layouts/
- default.vue在
default.vue
文件中定义你的布局:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<template>
<div>
<header>
<h1>我的应用程序</h1>
</header>
<main>
<slot />
</main>
<footer>
<p>© 2023 我的应用程序</p>
</footer>
</div>
</template>在你的页面中使用 Layouts:
1
2
3
4<template>
<h2>我的页面</h2>
<p>这是我的页面内容。</p>
</template>在这个示例中,我们在
layouts
目录中创建了一个名为default.vue
的布局,并在其中定义了一个包含header
、main
和footer
的结构。在页面中,我们可以使用<slot />
插槽来显示页面的内容。
Modules
Modules 是一种在 Nuxt 中扩展应用程序功能的方式,它们可以让你在整个应用程序中使用自定义的功能或第三方插件。在 Nuxt 3 中,你可以使用 modules
目录或 nuxt.config.ts
文件来注册本地或第三方模块。
以下是一个简单的 Modules 示例:
创建一个名为
modules
的目录,并在其中创建一个名为example.ts
的文件:1
2
3modules/
- example.ts在
example.ts
文件中定义你的模块:1
2
3
4
5
6
7
8import { ModuleOptions } from '@nuxt/types'
export default function exampleModule(options: ModuleOptions) {
this.nuxt.hook('render:route', (route) => {
console.log(`渲染路由:${route.fullPath}`)
})
}在这个示例中,我们创建了一个名为
exampleModule
的函数,它接收一个ModuleOptions
类型的参数。在函数中,我们使用this.nuxt.hook
钩子函数来注册一个名为render:route
的钩子,并在钩子函数中记录当前渲染的路由。在
nuxt.config.ts
文件中注册你的模块:1
2
3
4
5
6
7
8
9import { defineNuxtConfig } from 'nuxt'
import exampleModule from './modules/example'
export default defineNuxtConfig({
modules: [
exampleModule
]
})在这个示例中,我们在
nuxt.config.ts
文件中使用modules
数组来注册我们的exampleModule
模块。
4.4 CSS模块化与 scoped CSS
CSS 模块化
CSS 模块化是一种将 CSS 文件与 JavaScript 文件耦合在一起的技术,它可以帮助你在构建应用程序时更好地管理和组织你的样式表。在 Nuxt.js 3.4 中,你可以使用 <style module>
标签来定义 CSS 模块。
以下是一个简单的 CSS 模块化示例:
创建一个名为
components
的目录,并在其中创建一个名为MyComponent.vue
的文件:1
2
3components/
- MyComponent.vue在
MyComponent.vue
文件中定义你的组件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<template>
<div :class="$style.myComponent">
<h2 :class="$style.title">我的组件标题</h2>
<p :class="$style.content">我的组件内容。</p>
</div>
</template>
<style module>
.myComponent {
border: 1px solid #ccc;
padding: 16px;
}
.title {
color: #333;
font-size: 18px;
margin-top: 0;
}
.content {
color: #666;
font-size: 14px;
margin-bottom: 0;
}
</style>在这个示例中,我们在
MyComponent.vue
文件中使用<style module>
标签来定义我们的 CSS 模块。在 CSS 模块中,我们可以使用$style
对象来引用我们的样式类,并在组件的模板中使用这些类来应用样式。
scoped CSS
scoped CSS 是一种将样式限定在当前组件范围内的技术,它可以帮助你避免样式冲突和污染。在 Nuxt.js 3.4 中,你可以使用 scoped
属性来定义 scoped CSS。
以下是一个简单的 scoped CSS 示例:
创建一个名为
components
的目录,并在其中创建一个名为MyComponent.vue
的文件:1
2
3components/
- MyComponent.vue在
MyComponent.vue
文件中定义你的组件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20<template>
<div>
<h2 class="title">我的组件标题</h2>
<p class="content">我的组件内容。</p>
</div>
</template>
<style scoped>
.title {
color: #333;
font-size: 18px;
margin-top: 0;
}
.content {
color: #666;
font-size: 14px;
margin-bottom: 0;
}
</style>在这个示例中,我们在
MyComponent.vue
文件中使用scoped
属性来定义我们的 scoped CSS。在 scoped CSS 中,我们可以使用普通的 CSS 类来定义样式,这些样式将只应用于当前组件。
第五章:组件生命周期与优化
Nuxt 3 中的生命周期钩子
Nuxt 3 是基于 Vue 3 的服务器端渲染(SSR)框架,它提供了一套完整的生命周期钩子,允许开发者在不同阶段对组件进行操作。在 Nuxt 3 中,生命周期钩子的使用与 Vue 3 相似,但由于其 SSR 的特性,有一些区别。以下是 Nuxt 3 中常用的生命周期钩子:
setup
setup
是 Vue 3 Composition API 的入口,它是一个选项,作为组件的入口点,在组件创建之前执行。在 Nuxt 3 中,你可以在 setup
函数中定义组件的响应式数据和逻辑。
1 | export default defineComponent({ |
服务器端渲染相关钩子
- beforeRouteEnter: 在路由进入该组件的对应路由之前调用。
- beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用。
- beforeRouteLeave: 导航离开该组件的对应路由时调用。
客户端渲染相关钩子
以下是一些客户端特有的生命周期钩子:
- onBeforeMount: 在组件挂载之前调用。
- onMounted: 在组件挂载之后调用。
- onBeforeUpdate: 在组件更新之前调用。
- onUpdated: 在组件更新之后调用。
- onBeforeUnmount: 在组件卸载之前调用。
- onUnmounted: 在组件卸载之后调用。
created 和 beforeDestroy
在 Vue 2 中常用的 created
和 beforeDestroy
钩子,在 Vue 3 中仍然可以使用,但在 Nuxt 3 中,你可能会更倾向于使用 Composition API 中的生命周期函数。以下是它们在 Nuxt 3 中的对应:
- created: 可以使用
onBeforeMount
或onMounted
代替,因为 Nuxt 3 是基于 Vue 3 的,created
钩子在服务器端也会被调用,但它不保证在客户端执行。 - beforeDestroy: 可以使用
onBeforeUnmount
代替。
以下是如何在 Nuxt 3 中使用 onBeforeUnmount
的示例:
1 | export default defineComponent({ |
在 Nuxt 3 中,由于它支持 Vue 3 的 Composition API,建议使用新的生命周期函数,它们提供了更细粒度的控制,并允许你在不同的生命周期阶段更清晰地组织代码。
5.2 性能优化:懒加载、预渲染
Nuxt 3 提供了多种性能优化策略,包括懒加载(Lazy Loading)和预渲染(Prerendering)。以下是关于这两个方面的简要介绍:
1. 懒加载(Lazy Loading)
Nuxt 3 的懒加载功能允许你只加载用户需要的部分内容,而不是一次性加载整个页面。这主要通过使用 vue-lazyload
或 vue-meta
等库,以及 Nuxt 的官方 nuxt-lazyload
插件来实现。
- vue-lazyload: 可以在单个组件或整个页面上设置图片、子组件等元素的懒加载。
- vue-meta: 可以配置路由的
<meta>
标签,控制路由的预加载和懒加载。 - nuxt-lazyload: Nuxt 提供的官方插件,可以全局配置懒加载策略。
在 nuxt.config.js
中配置懒加载插件:
1 | export default { |
2. 预渲染(Prerendering)
Nuxt 3 支持两种预渲染方法:静态预渲染(Static Rendering)和服务器端渲染(Server-side Rendering,SSR)。
- 静态预渲染(Static Rendering) : 使用
nuxt generate
命令生成静态 HTML 版本的页面,这些页面在服务器上预先加载和解析,提高首屏加载速度。这对于 SEO 有显著优势,但不支持实时更新。 - 服务器端渲染(SSR) : 在用户访问页面时,Nuxt 会先在服务器上渲染整个页面,然后将渲染结果返回给客户端。这提供了更好的用户体验,尤其是对于动态内容,但服务器资源消耗较大。
为了优化 SSR,可以考虑以下策略:
- 使用
nuxt optimize
命令进行性能分析和优化。 - 避免在 SSR 中执行复杂的计算或网络请求。
- 使用
nuxt.config.js
中的generate
和build
配置,控制预渲染的范围和时机。
5.3 代码复用与模块化策略
Nuxt 3 支持多种代码复用与模块化策略,以帮助开发人员提高代码的可重用性和可维护性。以下是一些常用的 Nuxt 3 模块化策略:
1. 共享组件(Shared Components)
在 Nuxt 3 中,可以将组件放在 components
目录下,这些组件可以在整个应用中共享使用。例如,创建一个 components/MyButton.vue
文件,其中包含一个自定义按钮组件:
1 | <template> |
在其他组件中使用 MyButton
组件:
1 | <template> |
2. 插件(Plugins)
Nuxt 3 支持使用插件来扩展应用的功能。可以在 plugins
目录下创建插件文件,例如 plugins/my-plugin.js
:
1 | export default function ({ app }) { |
在 nuxt.config.js
中配置插件:
1 | export default { |
3. 模块(Modules)
Nuxt 3 支持使用模块来扩展应用的功能。可以在 modules
目录下创建模块文件,例如 modules/my-module.js
:
1 | export default function (moduleOptions) { |
在 nuxt.config.js
中配置模块:
1 | export default { |
4. 布局(Layouts)
Nuxt 3 支持使用布局来实现页面的通用结构。可以在 layouts
目录下创建布局文件,例如 layouts/default.vue
:
1 | <template> |
在页面组件中使用布局:
1 | <template> |
5. 存储(Store)
Nuxt 3 支持使用 Vuex 实现应用的状态管理。可以在 store
目录下创建模块文件,例如 store/index.js
:
1 | export const state = () => ({ |
在页面组件中使用存储:
1 | <template> |
第6章:组件测试与维护
6.1 使用 Vue Test Utils 进行单元测试
Vue Test Utils 是 Vue.js 官方提供的测试工具库,用于编写 Vue.js 组件的单元测试。在 Nuxt 3 中,可以使用 Vue Test Utils 来测试组件的行为和状态。
首先,需要安装 Vue Test Utils 和一些其他依赖库:
1 | npm install --save-dev @vue/test-utils vitest |
然后,在项目根目录下创建一个 tests
目录,并在其中创建一个 unit
目录,用于存放单元测试文件。例如,测试 components/MyButton.vue
组件:
1 | <template> |
创建一个 tests/unit/MyButton.spec.js
文件,用于测试 MyButton
组件:
1 | import { mount } from '@vue/test-utils'; |
最后,在 package.json
中配置测试命令:
1 | { |
运行测试命令:
1 | npm test |
6.2 使用 Storybook 进行组件开发与文档化
Storybook 是一个用于开发和文档化 UI 组件的工具。在 Nuxt 3 中,可以使用 Storybook 来开发和文档化组件。
首先,需要安装 Storybook 和一些其他依赖库:
1 | npx sb init --builder @storybook/builder-webpack5 --typescript |
然后,在项目根目录下创建一个 .storybook
目录,用于存放 Storybook 配置文件。例如,创建一个 .storybook/main.js
文件,用于配置 Storybook:
1 | module.exports = { |
在 components
目录下创建一个 MyButton.stories.ts
文件,用于定义 MyButton
组件的 Story:
1 | import MyButton from './MyButton.vue'; |
最后,在 package.json
中配置 Storybook 命令:
1 | { |
运行 Storybook 命令:
1 | npm run storybook |
6.3 维护与更新最佳实践
在 Nuxt 3 中开发和维护组件时,需要遵循一些最佳实践,以保证组件的可重用性和可维护性。
- 使用组件库:使用一些已有的组件库,如 Vuetify、Bootstrap-Vue 等,可以减少开发和维护的工作量。
- 使用组件 props:使用组件 props 可以使组件更加灵活和可重用。
- 使用组件 slot:使用组件 slot 可以使组件更加灵活和可扩展。
- 使用组件事件:使用组件事件可以使组件更加交互和可响应。
- 使用组件样式:使用组件样式可以使组件更加美观和一致。
- 使用组件测试:使用组件测试可以使组件更加可靠和可维护。
- 使用组件文档化:使用组件文档化可以使组件更加易于理解和使用。
- 使用组件更新:使用组件更新可以使组件更加新颖和有用。
往期文章推荐:
- Nuxt.js 深入浅出:目录结构与文件组织详解 | cmdragon’s Blog
- 友情链接 | cmdragon’s Blog
- 安装 Nuxt.js 的步骤和注意事项 | cmdragon’s Blog
- 探索Web Components | cmdragon’s Blog
- Vue微前端架构与Qiankun实践理论指南 | cmdragon’s Blog
- Vue 3深度探索:自定义渲染器与服务端渲染 | cmdragon’s Blog
- Tailwind CSS 响应式设计实战指南 | cmdragon’s Blog
- Tailwind CSS 实战指南:快速构建响应式网页设计 | cmdragon’s Blog
- Vue 3与ESLint、Prettier:构建规范化的前端开发环境 | cmdragon’s Blog
- Vue TypeScript 实战:掌握静态类型编程 | cmdragon’s Blog
- Vue CLI 4与项目构建实战指南 | cmdragon’s Blog