组件
components/
目录中放置所有 Vue 组件。Nuxt 会自动导入此目录中的所有组件(以及您可能使用的任何模块注册的组件)。
-| components/
---| AppHeader.vue
---| AppFooter.vue
<template>
<div>
<AppHeader />
<NuxtPage />
<AppFooter />
</div>
</template>
组件名称
如果您的组件位于嵌套目录中,例如
-| components/
---| base/
-----| foo/
-------| Button.vue
… 那么组件的名称将基于其自身的路径目录和文件名,重复的段将被删除。因此,组件的名称将是
<BaseFooButton />
Button.vue
重命名为 BaseFooButton.vue
。如果要仅根据组件名称(而不是路径)自动导入组件,则需要使用配置对象的扩展形式将 pathPrefix
选项设置为 false
export default defineNuxtConfig({
components: [
{
path: '~/components',
pathPrefix: false, },
],
});
这使用与 Nuxt 2 中相同的策略注册组件。例如,~/components/Some/MyComponent.vue
将可用作 <MyComponent>
而不是 <SomeMyComponent>
。
动态组件
如果要使用 Vue <component :is="someComputedComponent">
语法,则需要使用 Vue 提供的 resolveComponent
帮助器或直接从 #components
导入组件并将其传递给 is
属性。
例如
<script setup lang="ts">
import { SomeComponent } from '#components'
const MyButton = resolveComponent('MyButton')
</script>
<template>
<component :is="clickable ? MyButton : 'div'" />
<component :is="SomeComponent" />
</template>
resolveComponent
处理动态组件,请确保除了组件名称之外不插入任何内容,组件名称必须是字符串而不是变量。或者,虽然不推荐,但您可以全局注册所有组件,这将为所有组件创建异步块并使其在整个应用程序中可用。
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
您还可以通过将某些组件放在 ~/components/global
目录中或在文件名中使用 .global.vue
后缀来选择性地全局注册一些组件。如上所述,每个全局组件都在单独的块中渲染,因此请注意不要过度使用此功能。
global
选项也可以在每个组件目录中设置。动态导入
要动态导入组件(也称为延迟加载组件),您只需在组件名称前添加 Lazy
前缀即可。如果并非始终需要该组件,这将特别有用。
通过使用 Lazy
前缀,您可以延迟加载组件代码直到适当的时刻,这有助于优化 JavaScript 包大小。
<script setup lang="ts">
const show = ref(false)
</script>
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
</div>
</template>
直接导入
如果希望或需要绕过 Nuxt 的自动导入功能,也可以显式地从 #components
导入组件。
<script setup lang="ts">
import { NuxtLink, LazyMountainsList } from '#components'
const show = ref(false)
</script>
<template>
<div>
<h1>Mountains</h1>
<LazyMountainsList v-if="show" />
<button v-if="!show" @click="show = true">Show List</button>
<NuxtLink to="/">Home</NuxtLink>
</div>
</template>
自定义目录
默认情况下,仅扫描 ~/components
目录。如果要添加其他目录,或更改如何在该目录的子文件夹中扫描组件,可以将其他目录添加到配置中
export default defineNuxtConfig({
components: [
// ~/calendar-module/components/event/Update.vue => <EventUpdate />
{ path: '~/calendar-module/components' },
// ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog />
{ path: '~/user-module/components', pathPrefix: false },
// ~/components/special-components/Btn.vue => <SpecialBtn />
{ path: '~/components/special-components', prefix: 'Special' },
// It's important that this comes last if you have overrides you wish to apply
// to sub-directories of `~/components`.
//
// ~/components/Btn.vue => <Btn />
// ~/components/base/Btn.vue => <BaseBtn />
'~/components'
]
})
npm 包
如果要从 npm 包中自动导入组件,可以在本地模块中使用 addComponent
来注册它们。
import { addComponent, defineNuxtModule } from '@nuxt/kit'
export default defineNuxtModule({
setup() {
// import { MyComponent as MyAutoImportedComponent } from 'my-npm-package'
addComponent({
name: 'MyAutoImportedComponent',
export: 'MyComponent',
filePath: 'my-npm-package',
})
},
})
组件扩展名
默认情况下, nuxt.config.ts
中的 extensions 键 中指定的任何扩展名的文件都将被视为组件。如果需要限制应注册为组件的文件扩展名,可以使用组件目录声明的扩展形式及其 extensions
键
export default defineNuxtConfig({
components: [
{
path: '~/components',
extensions: ['.vue'], }
]
})
客户端组件
如果某个组件仅用于客户端渲染,可以在组件中添加 .client
后缀。
| components/
--| Comments.client.vue
<template>
<div>
<!-- this component will only be rendered on client side -->
<Comments />
</div>
</template>
#components
导入。从其真实路径显式导入这些组件不会将它们转换为仅客户端组件。.client
组件仅在挂载后才渲染。要使用 onMounted()
访问渲染的模板,请在 onMounted()
钩子的回调中添加 await nextTick()
。服务器组件
服务器组件允许在客户端应用程序中服务器渲染单个组件。即使您正在生成静态站点,也可以在 Nuxt 中使用服务器组件。这使得构建复杂的站点成为可能,这些站点混合了动态组件、服务器渲染的 HTML 甚至静态标记块。
服务器组件可以单独使用,也可以与 客户端组件 配合使用。
独立服务器组件
独立服务器组件将始终在服务器上渲染,也称为 Island 组件。
当它们的 props 更新时,这将导致网络请求,该请求将就地更新渲染的 HTML。
服务器组件目前处于实验阶段,要使用它们,您需要在 nuxt.config 中启用“组件岛”功能
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
现在您可以使用 .server
后缀注册仅服务器组件,并在应用程序中的任何位置自动使用它们。
-| components/
---| HighlightedMarkdown.server.vue
<template>
<div>
<!--
this will automatically be rendered on the server, meaning your markdown parsing + highlighting
libraries are not included in your client bundle.
-->
<HighlightedMarkdown markdown="# Headline" />
</div>
</template>
仅服务器组件在后台使用 <NuxtIsland>
,这意味着 lazy
属性和 #fallback
插槽都传递给它。
服务器组件内的客户端组件
experimental.componentIslands.selectiveClient
设置为 true。您可以通过在希望在客户端加载的组件上设置 nuxt-client
属性来部分水化组件。
<template>
<div>
<HighlightedMarkdown markdown="# Headline" />
<!-- Counter will be loaded and hydrated client-side -->
<Counter nuxt-client :count="5" />
</div>
</template>
experimental.componentIsland.selectiveClient
设置为 'deep'
时有效,并且由于它们是在服务器端渲染的,因此在客户端它们不会交互。服务器组件上下文
在渲染仅限服务器或岛屿组件时,<NuxtIsland>
会发出一个 fetch 请求,该请求会返回一个 NuxtIslandResponse
。(如果在服务器上渲染,则这是一个内部请求;如果在客户端导航上渲染,则您可以在网络选项卡中看到该请求。)
这意味着
- 将在服务器端创建一个新的 Vue 应用以创建
NuxtIslandResponse
。 - 在渲染组件时将创建一个新的“岛屿上下文”。
- 您无法从应用程序的其余部分访问“岛屿上下文”,也无法从岛屿组件访问应用程序其余部分的上下文。换句话说,服务器组件或岛屿组件与应用程序的其余部分是隔离的。
- 您的插件将在渲染岛屿时再次运行,除非它们已设置
env: { islands: false }
(您可以在对象语法插件中执行此操作)。
在岛屿组件中,您可以通过 nuxtApp.ssrContext.islandContext
访问其岛屿上下文。请注意,虽然岛屿组件仍被标记为实验性,但此上下文的格式可能会发生变化。
display: contents;
的 <div>
中。与客户端组件配对
在这种情况下,.server
+ .client
组件是组件的两个“部分”,可用于服务器端和客户端端组件的单独实现的高级用例。
-| components/
---| Comments.client.vue
---| Comments.server.vue
<template>
<div>
<!-- this component will render Comments.server on the server then Comments.client once mounted in the browser -->
<Comments />
</div>
</template>
内置 Nuxt 组件
Nuxt 提供了许多组件,包括 <ClientOnly>
和 <DevOnly>
。您可以在 API 文档中阅读有关它们的更多信息。
库作者
创建具有自动 tree-shaking 和组件注册的 Vue 组件库非常容易。✨
您可以使用 components:dirs
钩子扩展目录列表,而无需在您的 Nuxt 模块中进行用户配置。
想象一下这样的目录结构
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.js
-| pages/
---| index.vue
-| nuxt.config.js
然后在 awesome-ui/nuxt.js
中,您可以使用 components:dirs
钩子
import { defineNuxtModule, createResolver } from '@nuxt/kit'
export default defineNuxtModule({
hooks: {
'components:dirs': (dirs) => {
const { resolve } = createResolver(import.meta.url)
// Add ./components dir to the list
dirs.push({
path: resolve('./components'),
prefix: 'awesome'
})
}
}
})
就是这样!现在,在您的项目中,您可以在 nuxt.config
文件中将您的 UI 库作为 Nuxt 模块导入
export default defineNuxtConfig({
modules: ['awesome-ui/nuxt']
})
...并直接在我们的 pages/index.vue
中使用模块组件(以 awesome-
为前缀)。
<template>
<div>
My <AwesomeButton>UI button</AwesomeButton>!
<awesome-alert>Here's an alert!</awesome-alert>
</div>
</template>
它将仅在使用时自动导入组件,并在更新 node_modules/awesome-ui/components/
中的组件时支持 HMR。