熟悉 Vue 的朋友對於 Components(元件)想必都不陌生,它是 Vue 中的一個重要概念和核心功能,將網頁元素拆分成多個獨立的小部分,再利用這些元件來組合成完整的頁面,每個元件都可以被重複使用,且包含自己的模板、資料和程式碼邏輯。
Nuxt 同樣具有元件的概念,除了介紹元件的建立與使用之外,還會更深入的討論 Nuxt 3 Components 的特性與不同的運用方式。
在專案目錄中建立 components/
資料夾,新增一個 Card.vue
元件:
// components/Card.vue
<template>
<div class="card">
<div>my card !</div>
</div>
</template>
<style scoped>
.card {
border-radius: 4px;
padding: 2rem;
margin: 2rem;
box-shadow: 2px 2px 5px #4682b430;
background: LightBlue;
}
</style>
別忘了 Auto-imports 特性可以讓我們解放雙手,無需再手動引入元件即可使用,而元件的名稱則對應著該檔案名。
// app.vue
<template>
<div>
<Card />
</div>
</template>
如果想要拆分得更細呢?下面範例將卡片拆成兩個部分:
// components/card/Header.vue
<template>
<h1 class="card-header">Card Title</h1>
</template>
<style scoped>
.card-header {
color: steelBlue;
}
</style>
// components/card/Content.vue
<template>
<div>card content</div>
</template>
記得建立一個 Index.vue
來裝卡片所需的元件。
// components/card/Index.vue
<template>
<div class="card">
<CardHeader />
<CardContent />
</div>
</template>
<style scoped>
.card {
border-radius: 4px;
padding: 2rem;
margin: 2rem;
box-shadow: 2px 2px 5px #4682b430;
background: LightBlue;
}
</style>
使用 <Card />
元件即為 components/card/Index.vue
// app.vue
<template>
<div>
<Card />
</div>
</template>
巢狀結構時的元件名稱規則會是 目錄名 + 檔案名,若有重複字句將會自動刪除。components/base/form/Input.vue
或 components/base/form/BaseFormInput.vue
元件的名稱都會是 <BaseFormInput>
。
情境一:兩個同層的元件
同時存在 components/base/form/Input.vue
和 components/base/form/BaseFormInput.vue
。
// components/base/form/Input.vue
<template>
<div> Input </div>
</template>
// components/base/form/BaseFormInput.vue
<template>
<div> BaseFormInput </div>
</template>
// app.vue
<template>
<BaseFormInput />
</template>
被渲染的元件為 components/base/form/BaseFormInput.vue
。
情境二:兩個不同層的元件
同時存在 components/base/form/Input.vue
和 components/BaseFormInput.vue
。
// components/base/form/Input.vue
<template>
<div> Input </div>
</template>
// components/BaseFormInput.vue
<template>
<div> BaseFormInput </div>
</template>
// app.vue
<template>
<BaseFormInput />
</template>
被渲染的元件為 components/BaseFormInput.vue
。
由以上兩個例子可以發現,自動載入的順序是依照資料夾的層級跟名稱,所以會優先使用先被載入的元件。
如果不想要元件名是目錄名 + 檔案名也可以經由設定關掉。
export default defineNuxtConfig({
components: [
{
path: '~/components',
pathPrefix: false,
},
],
});
Vue 中的 <component :is="someComputedComponent">
語法用來動態的切換元件,在 Nuxt 中實現:
resolveComponent
先建立了兩個元件分別是 components/menu/Cake.vue
與 components/menu/Drinks.vue
,並使用 resolveComponent()
來製作切換效果:
// app.vue
<template>
<div>
<button @click="menu = 'cake'">Cake Menu</button>
<button @click="menu = 'drinks'">Drinks Menu</button>
<component :is="menu === 'cake' ? MenuCake : MenuDrinks" />
</div>
</template>
<script setup lang="ts">
const menu = ref("cake");
const MenuCake = resolveComponent("MenuCake");
const MenuDrinks = resolveComponent("MenuDrinks");
</script>
#components
也可使用 #components
手動引入,效果會是一樣的。
// app.vue
<template>
<div>
<button @click="menu = 'cake'">Cake Menu</button>
<button @click="menu = 'drinks'">Drinks Menu</button>
<component :is="menu === 'cake' ? MenuCake : MenuDrinks" />
</div>
</template>
<script setup lang="ts">
const menu = ref("cake");
import { MenuCake, MenuDrinks } from "#components"
</script>
又稱為 lazy-loading,僅在需要時載入特定的元件,有助於改善初始頁面載入效能。
要實現動態載入,只需在使用元件時加上前綴 Lazy
,將會在符合條件時才請求該元件,並且能夠降低首次進入畫面時所需載入的 JavaScript 程式碼大小。擁有大量元件的情況下可提高應用程式性能和效率,同時也能為使用者提供更佳的體驗。
可以看到初始進入頁面時就請求了 Input.vue
。
Lazy
達到動態載入// app.vue
<template>
<div>
<button @click="input = !input">open the input</button>
<LazyInput v-if="input" />
</div>
</template>
<script setup lang="ts">
const input = ref(false);
</script>
初始時並無請求,而是在按下按鈕使得該元件滿足條件時才發出。
今天介紹了 Components 的使用方法,明天會介紹 Nuxt 3 裡一個重要的元件 <ClientOnly>
。
Components Directory
Vue3 + Vite 快速上手 Get Startrd EP9 - Nuxt3 初體驗 ! 第一季完結篇!
Nuxt 3 元件 (Components)
說好的 window 和 document 呢?