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
文件看一看真的要開始做一些範例 不然好想睡覺唷~週末愉快!







1會員
24內容數
分享生活趣事~
留言0
查看全部
發表第一個留言支持創作者!
卡關的人生 的其他內容
介紹如何使用 ref 屬性來獲取 DOM 元素或子組件的引用,並展示了在模板中使用 <template> 標籤來定義 HTML 結構。講解了在 Composition API 中透過 useTemplateRef 獲取引用。在 v-for 內使用 ref 生成引用陣列和綁定函數作為 ref 的方式。
在 Vue.js 中,watch 是用來監控數據變化並執行副作用的工具。副作用指的是函數對外部狀態的變更,例如更新 DOM、進行網絡請求或修改全局變量。watch 允許我們在數據變化時自動響應,這對於處理異步操作和更新狀態非常有用。它也支持深層監聽和清理功能,能夠應對複雜的副作用場景。
在這篇文章中,探討了 Vue 組件的生命周期鉤子以及它們在不同階段的應用。每個 Vue 組件在創建時,會經歷一系列初始化步驟,這些步驟中會執行特定的生命週期鉤子函數,例如 onMounted、onUpdated 和 onUnmounted 等。這些鉤子允許開發者在組件的特定階段插入自定義代碼。
使用 v-bind 可以將 HTML 屬性、樣式或類別綁定到 Vue 的數據,實現單向數據綁定。而 v-model 則是用於表單元素的雙向數據綁定,使輸入和數據同步更新。使用 v-bind 可以讓我們綁定非字符串值,例如布爾值或對象,從而在處理更複雜的應用場景時更為靈活。
Vue.js 的事件修飾符提供了一種簡化和直觀的方式來處理事件。與傳統 JavaScript 中需要手動檢查條件和處理事件相比,Vue 的修飾符(如 .prevent、.stop、.enter)使代碼更加清晰和易於管理。這些修飾符直接在模板中指定事件行為,減少了樣板代碼,提升了可讀性。
v-for 用於渲染陣列或物件列表,支持索引和嵌套。使用 key 來提高渲染效率。v-if 和 v-for 不應同時在同一節點上使用。
介紹如何使用 ref 屬性來獲取 DOM 元素或子組件的引用,並展示了在模板中使用 <template> 標籤來定義 HTML 結構。講解了在 Composition API 中透過 useTemplateRef 獲取引用。在 v-for 內使用 ref 生成引用陣列和綁定函數作為 ref 的方式。
在 Vue.js 中,watch 是用來監控數據變化並執行副作用的工具。副作用指的是函數對外部狀態的變更,例如更新 DOM、進行網絡請求或修改全局變量。watch 允許我們在數據變化時自動響應,這對於處理異步操作和更新狀態非常有用。它也支持深層監聽和清理功能,能夠應對複雜的副作用場景。
在這篇文章中,探討了 Vue 組件的生命周期鉤子以及它們在不同階段的應用。每個 Vue 組件在創建時,會經歷一系列初始化步驟,這些步驟中會執行特定的生命週期鉤子函數,例如 onMounted、onUpdated 和 onUnmounted 等。這些鉤子允許開發者在組件的特定階段插入自定義代碼。
使用 v-bind 可以將 HTML 屬性、樣式或類別綁定到 Vue 的數據,實現單向數據綁定。而 v-model 則是用於表單元素的雙向數據綁定,使輸入和數據同步更新。使用 v-bind 可以讓我們綁定非字符串值,例如布爾值或對象,從而在處理更複雜的應用場景時更為靈活。
Vue.js 的事件修飾符提供了一種簡化和直觀的方式來處理事件。與傳統 JavaScript 中需要手動檢查條件和處理事件相比,Vue 的修飾符(如 .prevent、.stop、.enter)使代碼更加清晰和易於管理。這些修飾符直接在模板中指定事件行為,減少了樣板代碼,提升了可讀性。
v-for 用於渲染陣列或物件列表,支持索引和嵌套。使用 key 來提高渲染效率。v-if 和 v-for 不應同時在同一節點上使用。
你可能也想看
Google News 追蹤
Thumbnail
本專欄將提供給您最新的市場資訊、產業研究、交易心法、精選公司介紹,以上內容並非個股分析,還請各位依據自身狀況作出交易決策。歡迎訂閱支持我,獲得相關內容,也祝您的投資之路順遂! 每年 $990 訂閱方案👉 https://reurl.cc/VNYVxZ 每月 $99 訂閱方案👉https://re
Thumbnail
CSS 盒模型是理解和設計網頁佈局的核心概念。它包括元素的內容、填充、邊框和外邊距。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
※ 視圖模板 視圖模板(View Templates) 是在 MVC 架構中負責展示數據的 HTML 文件,包含模板語法,用於在渲染時插入實際數據。它們的主要目的是分離數據與展示邏輯,讓代碼更加模塊化和易於維護。 視圖模板設計和使用的核心理念,就是「重複的事情不要重複做、效益最大化、有效利用資源
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
套件(Package)是將程式或程式庫進行組織、分發和共享的一種方式。在軟體開發中,套件通常包含了相關的程式碼、資源文件和元數據,並提供了統一的名稱空間和版本管理。
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
我們在實作中,難免會遇到在不同組件中,卻有需求相同的資料格式,因此 mixins 可以達到我們的需求,除了 data 以外也包含了 methods 可以共用,舉例來說,學生資料可能會在,班級跟社團內被使用,當我們要撰寫元件時,就可以省略多餘的 data 定義。
Thumbnail
本專欄將提供給您最新的市場資訊、產業研究、交易心法、精選公司介紹,以上內容並非個股分析,還請各位依據自身狀況作出交易決策。歡迎訂閱支持我,獲得相關內容,也祝您的投資之路順遂! 每年 $990 訂閱方案👉 https://reurl.cc/VNYVxZ 每月 $99 訂閱方案👉https://re
Thumbnail
CSS 盒模型是理解和設計網頁佈局的核心概念。它包括元素的內容、填充、邊框和外邊距。
Thumbnail
各位使用 Vue.js 開發的小夥伴們,你們都怎麼實作父子層組件資料的雙向綁定呢?如果你還在寫 prop + emit 的話,不妨進來看看吧。
Thumbnail
切換頁面卡卡有很多種原因,這裡舉的例子只針對元件太大的情境。 除了想辦法拆分外,還有一個方法就是利用 Vue 的 Async Component。
Thumbnail
※ 視圖模板 視圖模板(View Templates) 是在 MVC 架構中負責展示數據的 HTML 文件,包含模板語法,用於在渲染時插入實際數據。它們的主要目的是分離數據與展示邏輯,讓代碼更加模塊化和易於維護。 視圖模板設計和使用的核心理念,就是「重複的事情不要重複做、效益最大化、有效利用資源
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
套件(Package)是將程式或程式庫進行組織、分發和共享的一種方式。在軟體開發中,套件通常包含了相關的程式碼、資源文件和元數據,並提供了統一的名稱空間和版本管理。
Thumbnail
平常我們在 html 上常看到的例如 v-for、v-model 等等... 也是VUE已經幫我們定義好的指令,而這次我們可以依這自己的需求來建立。 此功能屬於較進階的功能,因此實戰中會比較少見,市面上還是有不少完善的套件能達到同樣效果,建議可以先往這方面察找
Thumbnail
我們在實作中,難免會遇到在不同組件中,卻有需求相同的資料格式,因此 mixins 可以達到我們的需求,除了 data 以外也包含了 methods 可以共用,舉例來說,學生資料可能會在,班級跟社團內被使用,當我們要撰寫元件時,就可以省略多餘的 data 定義。