EP14 - 組件基礎

更新於 發佈於 閱讀時間約 1 分鐘
Components Basics 看了這麼久才了解組件基礎!
看來還有很多不了解的啊~
等這些基礎內容看完再來做範例應該可以比較清楚吧www

組件允許我們將 UI 分割成獨立且可重複使用的部分,並以獨立的方式思考每個部分。應用程序通常組織成一個嵌套組件的樹狀結構:

raw-image

這與嵌套原生 HTML 元素非常相似,但 Vue 實現了自己的組件模型,使我們能夠在每個組件中封裝自定義內容和邏輯。Vue 也能很好地與原生 Web Components 協作。如果您對 Vue 組件和原生 Web Components 之間的關係感到好奇,請在此處閱讀更多

定義組件 - Defining a Component

在使用構建步驟時,我們通常在一個專用的文件中定義每個 Vue 組件,使用 .vue 擴展名,這被稱為單文件組件 (SFC):

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>

在不使用構建步驟的情況下,可以將 Vue 組件定義為包含 Vue 特定選項的普通 JavaScript 物件:

import { ref } from 'vue'

export default {
setup() {
const count = ref(0)
return { count }
},
template: `
<button @click="count++">
You clicked me {{ count }} times.
</button>`
// 也可以針對 DOM 中的模板元素:
// template: '#my-template-element'
}

這裡的模板內嵌為 JavaScript 字串,Vue 會即時編譯。您也可以使用 ID 選擇器指向一個元素 (通常是原生的 <template> 元素) - Vue 將使用其內容作為模板來源。

上述示例定義了一個單一的組件並將其作為 .js 文件的默認導出,但您可以使用命名導出從同一文件中導出多個組件。

使用組件 - Using a Component

提示

在本文件其餘部分,我們將使用 SFC 語法,無論是否使用構建步驟,關於組件的概念都是相同的。在示例部分,展示了這兩種情況下的組件使用。

要使用子組件,我們需要在父組件中導入它。假設我們將計數器組件放在一個名為 ButtonCounter.vue 的文件中,該組件將作為該文件的默認導出:

<script setup>
import ButtonCounter from './ButtonCounter.vue'
</script>

<template>
<h1>Here is a child component!</h1>
<ButtonCounter />
</template>

使用 <script setup>,導入的組件會自動在模板中可用。

也可以全局註冊一個組件,使其在整個應用中的所有組件中都可用,而無需導入。在專門的組件註冊部分中討論了全局註冊與局部註冊的優缺點。

組件可以多次重用:

<template>
<h1>Here are many child components!</h1>
<ButtonCounter />
<ButtonCounter />
<ButtonCounter />
</template>

Try it in the playground

注意,當點擊按鈕時,每個按鈕都保持自己的獨立計數。這是因為每次使用組件時,會創建其新實例。

在 SFC 中,建議使用 PascalCase 標籤名來區分子組件和原生 HTML 元素。儘管原生 HTML 標籤名不區分大小寫,但 Vue SFC 是編譯格式,因此我們可以在其中使用區分大小寫的標籤名。我們還可以使用 / > 來關閉標籤。

如果您直接在 DOM 中編寫模板(例如作為原生 <template> 元素的內容),模板將受到瀏覽器原生 HTML 解析行為的約束。在這種情況下,您需要使用 kebab-case 和顯式閉合標籤來表示組件:

<!-- 如果此模板在 DOM 中編寫 -->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>

查看更多有關 DOM 模板解析的注意事項。

傳遞 Props - Passing Props

如果我們在構建一個部落格,我們可能需要一個代表部落格文章的組件。我們希望所有的部落格文章共享相同的視覺佈局,但內容不同。這樣的組件如果不能傳遞數據(例如我們要顯示的特定文章的標題和內容),那麼它就不會有用處。而這正是 props 的作用所在。

Props 是可以在組件上註冊的自定義屬性。要將標題傳遞給我們的部落格文章組件,我們必須在該組件接受的 props 列表中聲明它,使用 defineProps 巨集:

<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
</script>

<template>
<h4>{{ title }}</h4>
</template>

defineProps 是一個僅在 <script setup> 中可用的編譯時巨集,不需要顯式導入。聲明的 props 將自動暴露給模板。defineProps 也返回一個包含所有傳遞給組件的 props 的對象,因此如果需要,我們可以在 JavaScript 中訪問它們:

const props = defineProps(['title'])
console.log(props.title)

另見: Typing Component Props

如果您不使用 <script setup>,則應使用 props 選項來聲明 props,並且 props 對象將作為第一個參數傳遞給 setup():

export default {
props: ['title'],
setup(props) {
console.log(props.title)
}
}

一個組件可以有任意多的 props,並且默認情況下,任何值都可以傳遞給任何 prop。

一旦註冊了 prop,您可以像這樣作為自定義屬性傳遞數據給它:

<template>
<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
</template>

然而,在一個典型的應用中,您可能在父組件中有一個帖子數組:

const posts = ref([
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
])

然後希望使用 v-for 為每個帖子渲染一個組件:

<template>
<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
</template>

Try it in the playground

注意如何使用 v-bind 語法 (:title="post.title") 來傳遞動態 prop 值。這在您無法提前知道要渲染的確切內容時特別有用。

現在您需要了解的 props 就這麼多,但閱讀完本頁並對其內容感到滿意後,我們建議稍後回來閱讀 props 的完整指南。

監聽事件 - Listening to Events

在開發 <BlogPost> 組件時,一些功能可能需要與父組件進行通信。例如,可能會決定加入一個無障礙功能來放大部落格文章的文本,同時保持頁面其他部分默認大小。

在父組件中,我們可以通過添加 postFontSize 的 ref 來支持這個功能:

const posts = ref([
/* ... */
])

const postFontSize = ref(1)

這可以在模板中用來控制所有部落客文章的字體大小:

<template>
<div :style="{ fontSize: postFontSize + 'em' }">
<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
</div>
</template>

現在我們在 <BlogPost> 組件的模板中添加一個按鈕:

<!-- BlogPost.vue, omitting <script> -->
<template>
<div class="blog-post">
<h4>{{ title }}</h4>
<button>Enlarge text</button>
</div>
</template>

按鈕目前還沒有功能,我們希望點擊按鈕時可以向父組件傳達應該放大所有文章的文本。為了解決這個問題,組件提供了一個自定義事件系統。父組件可以選擇使用 v-on@ 來監聽子組件實例上的任何事件,就像我們對待原生 DOM 事件一樣:

<template>
<BlogPost
...
@enlarge-text="postFontSize += 0.1"
/>
</template>

然後子組件可以通過調用內置的 $emit 方法來自己發出事件,傳遞事件名稱:

<!-- BlogPost.vue, omitting <script> -->
<template>
<div class="blog-post">
<h4>{{ title }}</h4>
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
</template>

由於有 @enlarge-text="postFontSize += 0.1" 監聽器,父組件會接收到該事件並更新 postFontSize 的值。

Try it in the playground

我們可以選擇使用 defineEmits 巨集來聲明發出的事件:

<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
defineEmits(['enlarge-text'])
</script>

這會記錄組件發出的所有事件並可選地對它們進行驗證。它還允許 Vue 避免隱式地將它們應用為子組件根元素的原生監聽器。

defineProps 類似,defineEmits 只能在 <script setup> 中使用,不需要導入。它返回的 emit 函數等同於 $emit 方法。它可以在組件的 <script setup> 部分用來發出事件,這裡無法直接訪問 $emit

<script setup>
const emit = defineEmits(['enlarge-text'])

emit('enlarge-text')
</script>

另見: Typing Component Emits

如果您不使用 <script setup>,可以使用 emits 選項來聲明發出的事件。您可以作為 setup 上下文的屬性(作為第二個參數傳遞給 setup())來訪問 emit 函數:

export default {
emits: ['enlarge-text'],
setup(props, ctx) {
ctx.emit('enlarge-text')
}
}

現在您需要了解的自定義組件事件就是這麼多,但閱讀完本頁並對其內容感到滿意後,我們建議稍後回來閱讀自定義事件的完整指南。

使用插槽的內容分發 - Content Distribution with Slots​

與 HTML 元素一樣,能夠將內容傳遞給組件通常是非常有用的,例如:

  <AlertBox>
Something bad happened.
</AlertBox>

這可能會渲染成這樣:

This is an Error for Demo Purposes

Something bad happened.

這可以透過 Vue 的自訂 <slot> 元素來實現:

<!-- AlertBox.vue -->
<template>
<div class="alert-box">
<strong>這是一個用於示範的錯誤訊息</strong>
<slot />
</div>
</template>

<style scoped>
.alert-box {
/* ... */
}
</style>

如上所示,我們使用 <slot> 作為內容的佔位符,就這樣,我們完成了!

Try it in the playground

這就是目前你需要知道的關於插槽的所有內容,但在你讀完這頁並對其內容感到熟悉後,我們建議你稍後再回來閱讀完整的插槽指南。

動態元件 - Dynamic Components

有時,動態切換元件是非常有用的,例如在分頁介面中:

Open example in the playground

上面的功能是透過 Vue 的 <component> 元素和特殊的 is 屬性來實現的:

<!-- 當 currentTab 改變時,元件會隨之改變 -->
<component :is="tabs[currentTab]"></component>

在上述範例中,傳遞給 :is 的值可以是:

  • 註冊元件的名稱字串,或
  • 實際匯入的元件物件

你也可以使用 is 屬性來創建常規的 HTML 元素。

在使用 <component :is="..."> 切換多個元件時,當切換離開時,該元件會被卸載。我們可以使用內建的 <KeepAlive> 元件來強制非活躍的元件保持「存活」狀態。

在 DOM 中的模板解析注意事項 - in-DOM Template Parsing Caveats​

如果你直接在 DOM 中編寫 Vue 模板,Vue 必須從 DOM 獲取模板字串。這會導致一些注意事項,因為瀏覽器的原生 HTML 解析行為。

提示

需注意,以下討論的限制僅適用於直接在 DOM 中編寫模板。如果你使用來自以下來源的字串模板,則不會受到這些限制的影響:

  • 單檔元件(Single-File Components)
  • 嵌入式模板字串(例如:template: '...'
  • <script type="text/x-template">

大小寫不敏感 - Case Insensitivity

HTML 標籤和屬性名稱對大小寫不敏感,因此瀏覽器會將任何大寫字元視為小寫。這意味著在使用 DOM 模板時,PascalCase 元件名稱和 camelCased 屬性名稱或 v-on 事件名稱都需要使用其 kebab-case(以連字符分隔)等效形式:

// JavaScript 中的 camelCase
const BlogPost = {
props: ['postTitle'],
emits: ['updatePost'],
template: `
<h3>{{ postTitle }}</h3>
`
}
<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>

自我閉合標籤 - Self Closing Tags

在之前的程式碼範例中,我們使用了自我閉合標籤來表示元件:

<MyComponent />

這是因為 Vue 的模板解析器會將 /> 視為結束任何標籤的指示,無論其類型如何。

然而,在 DOM 模板中,我們必須始終包含明確的結束標籤:

<my-component></my-component>

這是因為 HTML 規範僅允許少數特定元素省略結束標籤,最常見的為 <input><img>。對於所有其他元素,如果省略了結束標籤,原生 HTML 解析器會認為你從未終止開放標籤。例如,以下程式碼片段:

<my-component /> <!-- 我們打算在這裡關閉標籤... -->
<span>hello</span>

將被解析為:

<my-component>
<span>hello</span>
</my-component> <!-- 但瀏覽器會在這裡關閉它。 -->

元素放置限制 - Element Placement Restrictions

某些 HTML 元素,如 <ul><ol><table><select>,對其內部可以出現的元素有限制,而某些元素如 <li><tr><option> 僅能出現在特定的其他元素內。

這會在使用具有此類限制的元素的元件時導致問題。例如:

<table>
<blog-post-row></blog-post-row>
</table>

自訂元件 <blog-post-row> 將被提升為無效內容,導致最終渲染的輸出出現錯誤。我們可以使用特殊的 is 屬性作為變通方法:

<table>
<tr is="vue:blog-post-row"></tr>
</table>

提示

當在原生 HTML 元素上使用時,is 的值必須以 vue: 為前綴,才能被解釋為 Vue 元件。這是為了避免與原生自訂內建元素混淆。

這就是目前你需要了解的有關在 DOM 中的模板解析注意事項—實際上,這也是 Vue 基礎知識的結束。恭喜你!還有更多需要學習的內容,但首先,我們建議你休息一下,自己動手玩玩 Vue—建構一些有趣的東西,或者如果你還沒有的話,查看一些範例

一旦你對剛學到的知識感到熟悉,就可以繼續閱讀指南,深入了解元件的內容。

終於啃完基礎篇了嗎?一堆請你參考別的內容~
真的是會越看越頭大的文件,不是說好Vue比較簡單嗎?
看起來什麼東西都沒有這麼簡單www
文件看一看真的要開始做一些範例 不然好想睡覺唷~週末愉快!







留言
avatar-img
留言分享你的想法!
avatar-img
卡關的人生
2會員
71內容數
分享生活趣事~
卡關的人生的其他內容
2024/11/10
Vue 提供了多種動畫技術來提升應用程式的互動性,包括基於 CSS 類別的動畫、基於狀態的動畫,以及使用監視器來動畫化數值。基於類別的動畫可通過動態添加 CSS 類別來觸發,像是觸發按鈕搖動效果。基於狀態的動畫則是透過樣式綁定,根據互動動態調整元素的外觀,例如根據滑鼠位置改變背景顏色。
Thumbnail
2024/11/10
Vue 提供了多種動畫技術來提升應用程式的互動性,包括基於 CSS 類別的動畫、基於狀態的動畫,以及使用監視器來動畫化數值。基於類別的動畫可通過動態添加 CSS 類別來觸發,像是觸發按鈕搖動效果。基於狀態的動畫則是透過樣式綁定,根據互動動態調整元素的外觀,例如根據滑鼠位置改變背景顏色。
Thumbnail
2024/11/09
Web Components 是一組網頁原生 API,允許開發者創建可重複使用的自訂元素。Vue 與 Web Components 是互補的技術,Vue 支援整合和創建自訂元素。
Thumbnail
2024/11/09
Web Components 是一組網頁原生 API,允許開發者創建可重複使用的自訂元素。Vue 與 Web Components 是互補的技術,Vue 支援整合和創建自訂元素。
Thumbnail
2024/11/08
Vue 建議使用模板構建應用程式,但在需要 JavaScript 的全程式化功能時,渲染函數可派上用場。渲染函數通過 h() 函數創建 vnode,h 是 hyperscript 的簡寫,能生成 HTML 的 JavaScript。
Thumbnail
2024/11/08
Vue 建議使用模板構建應用程式,但在需要 JavaScript 的全程式化功能時,渲染函數可派上用場。渲染函數通過 h() 函數創建 vnode,h 是 hyperscript 的簡寫,能生成 HTML 的 JavaScript。
Thumbnail
看更多
你可能也想看
Thumbnail
大家好,我是一名眼科醫師,也是一位孩子的媽 身為眼科醫師的我,我知道視力發展對孩子來說有多關鍵。 每到開學季時,診間便充斥著許多憂心忡忡的家屬。近年來看診中,兒童提早近視、眼睛疲勞的案例明顯增加,除了3C使用過度,最常被忽略的,就是照明品質。 然而作為一位媽媽,孩子能在安全、舒適的環境
Thumbnail
大家好,我是一名眼科醫師,也是一位孩子的媽 身為眼科醫師的我,我知道視力發展對孩子來說有多關鍵。 每到開學季時,診間便充斥著許多憂心忡忡的家屬。近年來看診中,兒童提早近視、眼睛疲勞的案例明顯增加,除了3C使用過度,最常被忽略的,就是照明品質。 然而作為一位媽媽,孩子能在安全、舒適的環境
Thumbnail
我的「媽」呀! 母親節即將到來,vocus 邀請你寫下屬於你的「媽」故事——不管是紀錄爆笑的日常,或是一直想對她表達的感謝,又或者,是你這輩子最想聽她說出的一句話。 也歡迎你曬出合照,分享照片背後的點點滴滴 ♥️ 透過創作,將這份情感表達出來吧!🥹
Thumbnail
我的「媽」呀! 母親節即將到來,vocus 邀請你寫下屬於你的「媽」故事——不管是紀錄爆笑的日常,或是一直想對她表達的感謝,又或者,是你這輩子最想聽她說出的一句話。 也歡迎你曬出合照,分享照片背後的點點滴滴 ♥️ 透過創作,將這份情感表達出來吧!🥹
Thumbnail
組件組成一棵樹狀結構,類似於嵌套的 HTML 元素,但 Vue 提供了自定義內容和邏輯的封裝。通常我們會在專用的 .vue 文件中定義組件,並使用 <script setup> 來輕鬆管理狀態和事件。組件可以重複使用,並透過 props 傳遞數據,使用插槽實現內容分發。
Thumbnail
組件組成一棵樹狀結構,類似於嵌套的 HTML 元素,但 Vue 提供了自定義內容和邏輯的封裝。通常我們會在專用的 .vue 文件中定義組件,並使用 <script setup> 來輕鬆管理狀態和事件。組件可以重複使用,並透過 props 傳遞數據,使用插槽實現內容分發。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
套件(Package)是將程式或程式庫進行組織、分發和共享的一種方式。在軟體開發中,套件通常包含了相關的程式碼、資源文件和元數據,並提供了統一的名稱空間和版本管理。
Thumbnail
套件(Package)是將程式或程式庫進行組織、分發和共享的一種方式。在軟體開發中,套件通常包含了相關的程式碼、資源文件和元數據,並提供了統一的名稱空間和版本管理。
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
Vue.js是一種基於MVVM的前端JavaScript框架,類似的框架有React、Angular等。 架設環境 安裝Visual Studio Code(https://code.visualstudio.com/) 安裝Node.js(https://nodejs.org/en/
Thumbnail
Vue.js是一種基於MVVM的前端JavaScript框架,類似的框架有React、Angular等。 架設環境 安裝Visual Studio Code(https://code.visualstudio.com/) 安裝Node.js(https://nodejs.org/en/
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
樣板模式的定義極為簡單,卻是大型系統程式、WEB/APP應用框架的設計核心,完美展現設計模式的價值: 簡單、高效、強大。
Thumbnail
這系列是我在 2023 六角學院 Vue作品實戰班的筆記,筆記以本人理解的方式記錄。此篇主題為 Slot Props 進階應用 ,其中包含單筆資料、多筆資料。
Thumbnail
這系列是我在 2023 六角學院 Vue作品實戰班的筆記,筆記以本人理解的方式記錄。此篇主題為 Slot Props 進階應用 ,其中包含單筆資料、多筆資料。
Thumbnail
前言 Vue 是一個現代開發框架,擁有完尚的生態系,讓我們可以將須多元件客製化,做出組件,並且可重複利用,高擴充性。在開發組件時,每個組件都擁有自己的生命周期,Vue 組件會偵測每個變數值,是否有變,並且更新內容,今天要一個一個了解 Vue 的生命週期,讓大家有更多認識。 Vue 的生命週期
Thumbnail
前言 Vue 是一個現代開發框架,擁有完尚的生態系,讓我們可以將須多元件客製化,做出組件,並且可重複利用,高擴充性。在開發組件時,每個組件都擁有自己的生命周期,Vue 組件會偵測每個變數值,是否有變,並且更新內容,今天要一個一個了解 Vue 的生命週期,讓大家有更多認識。 Vue 的生命週期
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News