iT邦幫忙

2023 iThome 鐵人賽

DAY 8
0
Vue.js

Nuxt 3 初學者指南:30天從基礎到實踐系列 第 8

Day 8 – Nuxt 3 Components(元件)

  • 分享至 

  • xImage
  •  

熟悉 Vue 的朋友對於 Components(元件)想必都不陌生,它是 Vue 中的一個重要概念和核心功能,將網頁元素拆分成多個獨立的小部分,再利用這些元件來組合成完整的頁面,每個元件都可以被重複使用,且包含自己的模板、資料和程式碼邏輯。

Nuxt 同樣具有元件的概念,除了介紹元件的建立與使用之外,還會更深入的討論 Nuxt 3 Components 的特性與不同的運用方式。

使用方法

Step 1

在專案目錄中建立 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>

Step 2

別忘了 Auto-imports 特性可以讓我們解放雙手,無需再手動引入元件即可使用,而元件的名稱則對應著該檔案名。

// app.vue
<template>
  <div>
    <Card />
  </div>
</template>

https://ithelp.ithome.com.tw/upload/images/20230922/20162805vh51edgzeP.png

巢狀

Step 1

如果想要拆分得更細呢?下面範例將卡片拆成兩個部分:

  • Header
// components/card/Header.vue
<template>
  <h1 class="card-header">Card Title</h1>
</template>
<style scoped>
.card-header {
  color: steelBlue;
}
</style>
  • Content
// components/card/Content.vue
<template>
  <div>card content</div>
</template>

Step 2

記得建立一個 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>

Step 3

使用 <Card /> 元件即為 components/card/Index.vue

// app.vue
<template>
  <div>
    <Card />
  </div>
</template>

https://ithelp.ithome.com.tw/upload/images/20230922/20162805yzOa5IxXVE.png

注意

巢狀結構時的元件名稱規則會是 目錄名 + 檔案名,若有重複字句將會自動刪除。
components/base/form/Input.vuecomponents/base/form/BaseFormInput.vue 元件的名稱都會是 <BaseFormInput>

Q:如果在不同的資料結構下,產生相同名稱的元件,會發生什麼事?

  • 情境一:兩個同層的元件

    同時存在 components/base/form/Input.vuecomponents/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>
    

    https://ithelp.ithome.com.tw/upload/images/20230922/20162805KZgSkw2GDw.png

    被渲染的元件為 components/base/form/BaseFormInput.vue

  • 情境二:兩個不同層的元件

    同時存在 components/base/form/Input.vuecomponents/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>
    

    https://ithelp.ithome.com.tw/upload/images/20230922/20162805zzebxxXS61.png

    被渲染的元件為 components/BaseFormInput.vue

    https://ithelp.ithome.com.tw/upload/images/20230922/20162805hhQtgwcDrf.png

    由以上兩個例子可以發現,自動載入的順序是依照資料夾的層級跟名稱,所以會優先使用先被載入的元件。

    如果不想要元件名是目錄名 + 檔案名也可以經由設定關掉。

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

動態元件

Vue 中的 <component :is="someComputedComponent"> 語法用來動態的切換元件,在 Nuxt 中實現:

resolveComponent

先建立了兩個元件分別是 components/menu/Cake.vuecomponents/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>

初始時並無請求,而是在按下按鈕使得該元件滿足條件時才發出。

🌞 Upcoming

今天介紹了 Components 的使用方法,明天會介紹 Nuxt 3 裡一個重要的元件 <ClientOnly>


參考資料

Components Directory
Vue3 + Vite 快速上手 Get Startrd EP9 - Nuxt3 初體驗 ! 第一季完結篇!
Nuxt 3 元件 (Components)
說好的 window 和 document 呢?


上一篇
Day 7 – Nuxt 3 Utils(實用函式)
下一篇
Day 9 – Nuxt 3 Components <ClientOnly>
系列文
Nuxt 3 初學者指南:30天從基礎到實踐30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言