透過超過 100 個技巧學習 Nuxt!

components

components/ 目錄是用來放置所有 Vue 元件的地方。

Nuxt 會自動匯入此目錄中的任何元件(以及您可能正在使用的任何模組所註冊的元件)。

目錄結構
-| components/
---| AppHeader.vue
---| AppFooter.vue
app.vue
<template>
  <div>
    <AppHeader />
    <NuxtPage />
    <AppFooter />
  </div>
</template>

元件名稱

如果您在巢狀目錄中有一個元件,例如

目錄結構
-| components/
---| base/
-----| foo/
-------| Button.vue

... 那麼元件的名稱將基於其自身的路徑目錄和檔案名稱,並刪除重複的區段。因此,元件的名稱將是

<BaseFooButton />
為了清楚起見,我們建議元件的檔案名稱與其名稱相符。因此,在上面的範例中,您可以將 Button.vue 重新命名為 BaseFooButton.vue

如果您希望僅根據名稱而非路徑自動匯入元件,則需要使用組態物件的擴充形式將 pathPrefix 選項設定為 false

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
pathPrefix
: false,
}, ], });

這會使用與 Nuxt 2 中相同的策略註冊元件。例如,~/components/Some/MyComponent.vue 將可用作 <MyComponent> 而不是 <SomeMyComponent>

動態元件

如果您想使用 Vue <component :is="someComputedComponent"> 語法,您需要使用 Vue 提供的 resolveComponent 輔助程式,或直接從 #components 匯入元件並將其傳遞到 is 屬性中。

例如

pages/index.vue
<script setup lang="ts">
import { SomeComponent } from '#components'

const MyButton = resolveComponent('MyButton')
</script>

<template>
  <component :is="clickable ? MyButton : 'div'" />
  <component :is="SomeComponent" />
</template>
如果您使用 resolveComponent 來處理動態元件,請確保只插入元件的名稱,該名稱必須是字串而不是變數。
觀看 Daniel Roe 關於 resolveComponent 的短片。

或者,雖然不建議,您可以全域註冊所有元件,這會為所有元件建立非同步區塊,並使它們在整個應用程式中可用。

  export default defineNuxtConfig({
    components: {
+     global: true,
+     dirs: ['~/components']
    },
  })

您也可以透過將它們放在 ~/components/global 目錄中,或在檔案名稱中使用 .global.vue 後綴,有選擇性地全域註冊某些元件。如上所述,每個全域元件都會在單獨的區塊中呈現,因此請小心不要過度使用此功能。

global 選項也可以針對每個元件目錄進行設定。

動態匯入

要動態匯入元件(也稱為延遲載入元件),您只需在元件的名稱中新增 Lazy 前綴即可。如果元件不是一直都需要,這特別有用。

透過使用 Lazy 前綴,您可以延遲載入元件程式碼直到正確的時間,這對於最佳化 JavaScript 套件大小可能很有幫助。

pages/index.vue
<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 匯入元件。

pages/index.vue
<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 目錄。如果您想新增其他目錄,或變更如何在該目錄的子資料夾中掃描元件,您可以將其他目錄新增至設定中

nuxt.config.ts
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 鍵的擴充形式

nuxt.config.ts
export default 
defineNuxtConfig
({
components
: [
{
path
: '~/components',
extensions
: ['.vue'],
} ] })

用戶端元件

如果元件僅要在用戶端呈現,您可以將 .client 後綴新增至您的元件。

目錄結構
| components/
--| Comments.client.vue
pages/example.vue
<template>
  <div>
    <!-- this component will only be rendered on client side -->
    <Comments />
  </div>
</template>
此功能僅適用於 Nuxt 自動導入和 #components 導入。從它們的實際路徑顯式導入這些元件不會將它們轉換為僅限客戶端的元件。
.client 元件僅在掛載後才會渲染。若要使用 onMounted() 存取渲染後的模板,請在 onMounted() Hook 的回呼中加入 await nextTick()
您也可以使用 <ClientOnly> 元件達到類似的效果。

伺服器元件

伺服器元件允許在客戶端應用程式中伺服器渲染個別元件。即使您正在產生靜態網站,也可以在 Nuxt 中使用伺服器元件。這使得構建混合動態元件、伺服器渲染 HTML 甚至靜態標記區塊的複雜網站成為可能。

伺服器元件可以單獨使用,也可以與客戶端元件配對使用。

觀看 Learn Vue 關於 Nuxt 伺服器元件的影片。
閱讀 Daniel Roe 的 Nuxt 伺服器元件指南。

獨立伺服器元件

獨立伺服器元件將始終在伺服器上渲染,也稱為 Islands 元件。

當它們的 props 更新時,這將導致一個網路請求,該請求會就地更新渲染的 HTML。

伺服器元件目前為實驗性功能,若要使用它們,您需要在 nuxt.config 中啟用 'component islands' 功能

nuxt.config.ts
export default 
defineNuxtConfig
({
experimental
: {
componentIslands
: true
} })

現在您可以使用 .server 後綴註冊僅限伺服器的元件,並在您的應用程式中的任何位置自動使用它們。

目錄結構
-| components/
---| HighlightedMarkdown.server.vue
pages/example.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 prop 和 #fallback slot 都會傳遞給它。

伺服器元件(和 Islands)必須具有單一的根元素。(HTML 註解也被視為元素。)
當在其他 Islands 中巢狀 Islands 時要小心,因為每個 Islands 都會增加一些額外開銷。
僅限伺服器的元件和 Islands 元件的大多數功能,例如 slots 和客戶端元件,僅適用於單一檔案元件。

伺服器元件內的客戶端元件

此功能需要在您的設定中將 experimental.componentIslands.selectiveClient 設定為 true。

您可以在想要在客戶端載入的元件上設定 nuxt-client 屬性,來部分注水(hydrate)元件。

components/ServerWithClient.vue
<template>
  <div>
    <HighlightedMarkdown markdown="# Headline" />
    <!-- Counter will be loaded and hydrated client-side -->
    <Counter nuxt-client :count="5" />
  </div>
</template>
這僅在伺服器元件中有效。客戶端元件的 Slots 僅在 experimental.componentIsland.selectiveClient 設定為 'deep' 時才有效,並且由於它們是在伺服器端渲染的,因此一旦在客戶端就無法互動。

伺服器元件 Context

當渲染僅限伺服器的或 Islands 元件時,<NuxtIsland> 會發出一個 fetch 請求,該請求會返回一個 NuxtIslandResponse。(如果是在伺服器上渲染,這是一個內部請求,如果是在客戶端導覽上渲染,則您可以在網路選項卡中看到該請求。)

這意味著

  • 將在伺服器端建立一個新的 Vue 應用程式,以建立 NuxtIslandResponse
  • 在渲染元件時,將建立一個新的「Island Context」。
  • 您無法從應用程式的其餘部分存取「Island Context」,並且您無法從 Island 元件存取應用程式其餘部分的 Context。換句話說,伺服器元件或 Island 與應用程式的其餘部分隔離
  • 您的外掛程式將在渲染 Island 時再次執行,除非它們設定了 env: { islands: false }(您可以在物件語法外掛程式中執行此操作)。

在 Island 元件中,您可以透過 nuxtApp.ssrContext.islandContext 存取其 Island Context。請注意,雖然 Island 元件仍標記為實驗性,但此 Context 的格式可能會變更。

Slots 可以是互動式的,並且被包裹在一個具有 display: contents;<div>

與客戶端元件配對

在這種情況下,.server + .client 元件是元件的兩個「一半」,可以用於伺服器端和客戶端上元件的單獨實作的高級使用案例。

目錄結構
-| components/
---| Comments.client.vue
---| Comments.server.vue
pages/example.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 文件中閱讀更多相關資訊。

文件 > API 中閱讀更多資訊。

函式庫作者

使用自動 tree-shaking 和元件註冊來建立 Vue 元件函式庫非常容易。✨

您可以使用 components:dirs Hook 來擴展目錄列表,而無需在您的 Nuxt 模組中進行使用者設定。

想像一下這樣的目錄結構

目錄結構
-| node_modules/
---| awesome-ui/
-----| components/
-------| Alert.vue
-------| Button.vue
-----| nuxt.js
-| pages/
---| index.vue
-| nuxt.config.js

然後在 awesome-ui/nuxt.js 中,您可以使用 components:dirs Hook

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 模組匯入

nuxt.config.ts
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。

文件 > 範例 > 功能 > 自動導入中閱讀和編輯即時範例。