[Vue3] 第二課 Vue 元件精通課

2024 年 1 月 23 日
文章摘要
FakeGPT
加載中...
此內容由人工不智慧生成。

Vue 元件基礎

在 Vue 中一直有一個論述,叫做:“Everything is components”(一切皆元件)。可見元件在 Vue 開發中舉足輕重的地位。那麼元件究竟是什麼呢?

我們可以把元件理解爲:同時含有 <template></template> 部分、<style></style> 部分、<script></script> 部分,實現從元素、樣式到邏輯處理的一站式完全功能體。 通常,這個功能體被定義在一個 .vue 檔案中。也就是說,我們可以認爲,一個 .vue 檔案就是一個元件。

例如,一個標準的頁面可以被分爲 header(頭部)、main(主要部分)、sidebar(側邊欄)、footer(尾部)。其中每一個部分,都有自己的元素(HTML)、樣式(Style)和邏輯(JavaScript),所以一個頁面可以就可以被分爲若干元件。同時,這個頁面在 Vue 中也是一個 .vue 檔案,故這個頁面也可以看作是一個大元件。因此,在學習的前期,我們不妨將元件分爲頁面元件功能元件 。頁面元件是 Mount 在路由中,顯示一整個頁面的元件,而功能元件則是放到頁面元件中,是頁面的某一部分。

宣告元件

我們明白了元件的概念,自然明白該怎樣去宣告元件。只需要新增一個 .vue 檔案,包含這三個部分,一個元件就被宣告了。

ButtonConter.vue
<script>
</script>
<template>
</template>
<style>
</style>

使用元件

一個元件被宣告之後,必須被放到頁面上,才能夠顯示出來。也就是將某個元件放到更大的元件中去。因此,我們需要在更大的元件中去引入並使用這個元件。

首先,我們要在元件的 <script></script> 部分引入該元件:

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

然後,我們可以在元件的 <template></template> 部分使用該元件:

<template>
<ButtonCounter/>
</template>

這樣,這個元件就會被添加到更大的元件中,可以在父元件的相應位置顯示了。

元件 Props

元件的一個重要的特性就是將一個功能的集合體抽離出來。抽離出來的東西具有可復現性。

例如,我們有一個元件,會在很多個頁面中都用到,但是每個頁面中,該元件展示的信息不一樣。那我們該怎麼做呢?難道要定義很多個元件嗎?當然不是。因爲該元件的基本結構都是確定的,只是其中微小的部分有差異。那這種情況下,我們就需要父元件告訴子元件,到底要展示什麼內容,也就是說,需要父元件向子元件中傳送 props(屬性)。

要實現這個過程,需要執行以下步驟:

  1. 在子元件中定義需要傳入的 props
<script>
import { defineProps } from 'vue';
const props = defineProps({
nihao: { // nihao 是需要傳入的 prop 名字
type: String, // prop 的類型
default: "" // prop 預設的值
}
})
</script>
<template>
<!-- 渲染到 template,直接寫 prop 的名字即可 -->
<div> {{ nihao }} </div>
</template>
  1. 在父元件中傳入這個 prop 的值
<template>
<Component nihao="你好"/>
<Component nihao="Hello"/>
<Component nihao="こんにちは"/>
</template>

渲染結果如下:

<div>你好</div>
<div>Hello</div>
<div>こんにちは</div>

上面的例子實現了從父元件向子元件傳送一個 String 類型的 prop 名叫 nihao,我們可以看到,當向子元件傳送不同的 prop 值,子元件渲染到頁面上的內容也不同。

如果我們想要將父元件中的一個 JS 變數作爲 prop 傳入子元件,我們也可以使用模板語法來完成:

<Component :nihao="variable"/>

這樣子,當 veriable 變數發生改變的時候,傳入子元件的 prop 也相應發生改變。如果你想要將數字或者 Boolean 等類型傳入子元件,就必須使用模板語法纔可以。因爲預設的靜態傳入方式只能向裏面傳送字串。

事件處理

如果說父元件向子元件交流是透過傳送 prop 實現的,那麼子元件如果有內容需要報告給父元件,又該怎麼做呢?是透過一個叫做事件處理的程式來進行的。

完成該過程有兩種辦法,第一種是比較簡單的方法,只能在子元件中某些元素觸發 JS 事件之後,向父元件傳送一些固定的內容。實現過程如下:

<button @click="$emit('event')">Click me</button>

使用 $emit() 來向父元件傳送資料。event 是事件的名字。

在父元件中,可以透過事件監聽來處理子元件傳入的資料:

<Component @event="func"/>
const func = () => {
console.log("Hello, world.")
}

以上表示,一旦有監聽到子元件的 event 事件,就執行 func 函式。

我們也可以在子元件向上傳送事件的過程中向上傳送資料:

<button @click="$emit('event', 1)">Click me</button>

event 是事件名稱,1 是要向上傳入的內容。該內容將作爲父元件中 func 函式的引數傳入。

<Component @event="func"/>
const func = (e) => {
console.log(e)
}

除了這種簡單的方式,我們還可以將 emit 寫在 JS 部分,這樣我們就不必拘泥於按鈕的點擊、輸入框的輸入等等,可以在任何想拋出事件的時候,就將事件拋給父元件。

// 定義emits
const emit_event = defineEmits(["event"])
// 拋出事件
onMounted(() => {
emit_event("event", 1)
})

元件v-model

我們上一節課有講到,v-model 用於模板和資料的雙向綁定。我們也可以在開發元件的時候,爲我們的元件添加上這一屬性。

當我們爲元件添加了這一屬性後,父元件綁定到子元件的這一變數就可以直接在子元件中使用了,就像是在子元件中宣告的一樣。在子元件中改變該變數的值,父元件中也會相應改變。

Child.vue
const model = defineModel()
const update_model = () => {
model ++
}

父元件中可以透過 v-model 綁定一個 JS 變數:

Father.vue
<template>
<Child v-model="val"/>
</template>

這樣,我們就透過 v-model,將父元件中 val 這個變數綁定到了子元件中 model 這個變數。也可以說,valmodel 是同一個變數,只不過在父元件和子元件中分別叫 valmodel 而已。

在子元件中執行的 update_model() 函式,在改變子元件 model 變數的同時,由於 model 變數和父元件 val 變數互相綁定,故父元件中 val 變數也同步改變。反之亦然。

關於元件 v-model 的其餘內容,包括元件多個 v-model 的實現,請讀者自行查閱 Vue 官方文檔。模式基本相同,在此不再贅述。

插槽(Slot)

還記得我們遙遠遙遠的第一節課上,我和各位有談過一件什麼事情嗎?

單葉標籤和雙葉標籤。

我曾經在課上說過,這兩個詞語是我自己創造出來的,但很應景。所謂的雙葉標籤,兩個標籤葉之間是可以包圍一些東西的,從而可以渲染到頁面上。而單葉標籤由於只有一個標籤葉,所以沒有辦法在其中夾東西。

不知道大家發現了沒有,在之前我們所定義的所有元件,在父元件中使用的時候,幾乎都是單葉元件,儘管元件也可以被寫成雙葉形式:

<Component></Component>

但是在這種情況下,裏面包圍的任何東西都是不會被顯示和渲染的。

要實現在裏面放東西,並且還能夠渲染到子元件的相應位置,我們就需要用到“插槽”這個東西。在子元件需要渲染的地方加上一個插槽,就可以引導着雙葉之間的內容渲染到相應的部位了。例如,我們在子元件中可以這樣宣告:

Child.vue
<div id="nihao">
<slot></slot>
</div>

然後在父元件中就可以在雙葉之間添加內容了:

Father.vue
<Child>
<span>你好!</span>
</Child>

<slot></slot>關鍵字即爲插槽的標誌,代表着父元件雙葉之間的內容將被替換到這裏。上述內容渲染之後是這樣的:

<div id="nihao">
<span>你好!</span>
</div>

可以看到,雙葉之間的內容被替換到了子元件中<slot></slot>的位置。

至於多插槽的配置,還請讀者自行查閱Vue官方文檔,文檔的內容很好理解。

重要的內置元件

在Vue框架中,有幾個元件是Vue官方幫我們寫好的,我們可以直接使用去實現相應的功能。下面筆者將介紹其中兩個使用比較廣泛的元件。

Transition

<Transition> 會在一個元素或元件進入和離開 DOM 時套用動畫。

進入或離開可以由以下的條件之一觸發:

  • 由 v-if 觸發的切換
  • 由 v-show 觸發的切換
  • 由特殊元素 <component> 切換的動態元件
  • 改變特殊的 key 屬性

其中,前兩項是我們比較常用的,第三項將在下一個內置元件中詳細介紹,最後一項不是很常見。

下面是官方文檔中提供給我們的用法案例:

<button @click="show = !show">Toggle</button>
<Transition>
<p v-if="show">hello</p>
</Transition>
/* 下面我们会解释这些 class 是做什么的 */
.v-enter-active,
.v-leave-active {
transition: opacity 0.5s ease;
}
.v-enter-from,
.v-leave-to {
opacity: 0;
}

下面我們來解釋一下這些 CSS 動畫效果的實現。 總共有 6 個應用於進入與離開過渡效果的 CSS class。

Vue Transition Component

上面這張圖片很好地展示了這個過程。因此,我們就可以在CSS中,將這些狀態或過程的CSS樣式都定義出來,這樣 Transition 元件就會幫我們實現這個過渡的過程。

這是官方文檔的解釋:

  1. v-enter-from:進入動畫的起始狀態。 在元素插入之前添加,在元素插入完成後的下一幀移除。

  2. v-enter-active:進入動畫的生效狀態。 應用於整個進入動畫階段。 在元素插入之前添加,在過渡或動畫完成之後移除。 這個 class 可以用來定義進入動畫的持續時間、延遲與速度曲線類型。

  3. v-enter-to:進入動畫的結束狀態。 在元素插入完成後的下一幀被添加 (也就是 v-enter-from 被移除的同時),在過渡或動畫完成之後移除。

  4. v-leave-from:離開動畫的起始狀態。 在離開過渡效果被觸發時立即添加,在一幀後被移除。

  5. v-leave-active:離開動畫的生效狀態。 應用於整個離開動畫階段。 在離開過渡效果被觸發時立即添加,在過渡或動畫完成之後移除。 這個 class 可以用來定義離開動畫的持續時間、延遲與速度曲線類型。

  6. v-leave-to:離開動畫的結束狀態。 在一個離開動畫被觸發後的下一幀被添加 (也就是 v-leave-from 被移除的同時),在過渡或動畫完成之後移除。

爲過渡效果命名

上面我們套用的動畫,包括我們寫的 CSS,是沒有命名的。如果我們有好幾個需要套用不同動畫的元素,這顯然是不夠的。因此,我們可以把每一個動畫效果命名,然後選擇每一個需要套用動畫的元素使用哪一個動畫效果。

例如,我們需要名叫 “fade” 的一套動畫,我們首先要在 CSS 中,把前面的效果 class 改成:

.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}

可以看到,僅僅只是 “v” 換成了需要命名的名字而已。

然後,我們可以在 <Transition> 元件的 name 屬性去套用這個命名:

<Transition name="fade">
...
</Transition>

KeepAlive

要明白這個元件的用處,我們首先要引入動態元件的概念。有些情況下,我們會需要在兩個元件之間互相切換,比如標籤頁。

在這種情況下,我們可以使用 <component> 標籤來代替不同的元件:

<component :is="activeComponent" />

其中,activeComponent 是一個 JS 變數,其值是已經引入的子元件的名字或者元件實例。

預設情況下,一個元件實例在被替換掉後會被銷毀。 這會導致它遺失其中所有已變更的狀態-當這個元件再一次被顯示時,會建立一個只帶有初始狀態的新實例。

在切換時建立新的元件實例通常是有意義的,但有些時候,我們的確想要元件能在被「切走」的時候保留它們的狀態。 要解決這個問題,我們可以用 <KeepAlive> 內建元件將這些動態元件包裝起來:

<KeepAlive>
<component :is="activeComponent" />
</KeepAlive>

元件庫

元件是功能的集合體,而許許多多這樣的元件放到一起,就形成了元件庫。Vue3 有大量的第三方元件庫,包含了許許多多可以使用的元件。這些元件庫極大拓展了 Vue3 的能力。

國內目前比較流行的元件庫是 Element Plus

[Vue3] 第二課 Vue 元件精通課
https://blog.kynix.tw/posts/1731045344843/
作者
Adrian Chen
建檔時間
2024 年 1 月 23 日
協議
BY-NC-SA 4.0
姓名標示-非商業性-相同方式分享 4.0 國際