Vue組件基礎
在Vue中一直有一個論述,叫做:“Everything is components”(一切皆組件)。可見組件在Vue開發中舉足輕重的地位。那麼組件究竟是什麼呢?
我們可以把組件理解爲:同時含有\\部分、\部分、\部分,實現從元素、樣式到邏輯處理的一站式完全功能體。 通常,這個功能體被定義在一個.vue
檔案中。也就是說,我們可以認爲,一個.vue檔案就是一個組件。
例如,一個標準的頁面可以被分爲header(頭部)、main(主要部分)、sidebar(側邊欄)、footer(尾部)。其中每一個部分,都有自己的元素(HTML)、樣式(Style)和邏輯(JavaScript),所以一個頁面可以就可以被分爲若干組件。同時,這個頁面在Vue中也是一個.vue檔案,故這個頁面也可以看作是一個大組件。因此,在學習的前期,我們不妨將組件分爲頁面組件 和功能組件 。頁面組件是Mount在路由中,顯示一整個頁面的組件,而功能組件則是放到頁面組件中,是頁面的某一部分。
定義組件
我們明白了組件的概念,自然明白該怎樣去定義組件。只需要新建一個.vue文件,包含這三個部分,一個組件就被定義好了。
1 | <!-- ButtonConter.vue --> |
使用組件
一個組件被定義了之後,必須被放到頁面上,才能夠顯示出來。也就是將某個組件放到更大的組件中去。因此,我們需要在更大的組件中去引入並使用這個組件。
首先,我們要在組件的<script></script>
部分引入該組件:
1 | <script setup> |
然後,我們可以在組件的<template></template>
部分使用該組件:
1 | <template> |
這樣,這個組件就會被添加到更大的組件中,可以在父組件的相應位置顯示了。
組件Props
組件的一個重要的特性就是將一個功能的集合體抽離出來。抽離出來的東西具有可復現性。
例如,我們有一個組件,會在很多個頁面中都用到,但是每個頁面中,該組件展示的信息不一樣。那我們該怎麼做呢?難道要定義很多個組件嗎?當然不是。因爲該組件的基本結構都是確定的,只是其中微小的部分有差異。那這種情況下,我們就需要父組件告訴子組件,到底要展示什麼內容,也就是說,需要父組件向子組件中傳送props(屬性)。
要實現這個過程,需要執行以下步驟:
- 在子組件中定義需要傳入的props
1 | <script> |
- 在父組件中傳入這個props的值
1 | <template> |
渲染結果如下:
1 | <div>你好</div> |
上面的例子實現了從父組件向子組件傳送一個String類型的props名叫nihao,我們可以看到,當向子組件傳送不同的props值,子組件渲染到頁面上的內容也不同。
如果我們想要將父組件中的一個JS變數作爲props傳入子組件,我們也可以使用模板語法來完成:
1 | <Component :nihao="variable"/> |
這樣子,當veriable變數發生改變的時候,傳入子組件的props也相應發生改變。如果你想要將數字或者Boolean等類型傳入子組件,就必須使用模板語法纔可以。因爲預設的靜態傳入方式只能向裏面傳送字串。
事件處理
如果說父組件向子組件交流是透過傳送props實現的,那麼子組件如果有內容需要報告給父組件,又該怎麼做呢?是透過一個叫做事件處理的程式來進行的。
完成該過程有兩種辦法,第一種是比較簡單的方法,只能在子組件中某些元素觸發JS事件之後,向父組件傳送一些固定的內容。實現過程如下:
1 | <button @click="$emit('event')">Click me</button> |
使用$emit()
來向父組件傳送資料。event是事件的名字。
在父組件中,可以透過事件監聽來處理子組件傳入的資料:
1 | <Component @event="func"/> |
1 | const func = () => { |
以上表示,一旦監聽到了子組件的event事件,就執行func函式。
我們也可以在子組件向上傳送事件的過程中向上傳送資料:
1 | <button @click="$emit('event', 1)">Click me</button> |
event是事件名稱,1是要向上傳入的內容。該內容將作爲父組件中func函式的引數傳入。
1 | <Component @event="func"/> |
1 | const func = (e) => { |
除了這種簡單的方式,我們還可以將emit寫在JS部分,這樣我們就不必拘泥於按鈕的點擊、輸入框的輸入等等,可以在任何想拋出事件的時候,就將事件拋給父組件。
1 | // 定義emits |
組件v-model
我們上一節課講過,v-model用於模板和資料的雙向綁定。我們也可以在開發組件的時候,爲我們的組件添加上這一屬性。
當我們爲組件添加了這一屬性後,父組件綁定到子組件的這一變數就可以直接在子組件中使用了,就像是在子組件中定義的一樣。在子組件中改變該變數的值,父組件中也會相應改變。
1 | // Child.vue |
父組件中可以透過v-model綁定一個JS變數:
1 | <!-- Father.vue --> |
這樣,我們就透過v-model,將父組件中val這個變數綁定到了子組件中model這個變數。也可以說,val和model是同一個變數,只不過在父組件和子組件中分別叫val和model而已。
在子組件中執行的update_model()函式,在改變子組件model變數的同時,由於model變數和父組件val變數互相綁定,故父組件中val變數也同步改變。反之亦然。
關於組件v-model的其餘內容,包括組件多個v-model的實現,請讀者自行查閱Vue官方文檔。模式基本相同,在此不再贅述。
插槽(Slot)
還記得我們遙遠遙遠的第一節課上,我和各位說了一件什麼事情嗎?
單葉標籤和雙葉標籤。
我曾經在課上說過,這兩個詞語是我自己創造出來的,但很應景。所謂的雙葉標籤,兩個標籤葉之間是可以裹挾一些東西的,從而可以渲染到頁面上。而單葉標籤由於只有一個標籤葉,所以沒有辦法在其中夾東西。
不知道大家發現了沒有,在之前我們所定義的所有組件,在父組件中使用的時候,幾乎都是單葉組件,儘管組件也可以被寫成雙葉形式:
1 | <Component></Component> |
但是在這種情況下,裏面夾任何的東西都是不會被顯示和渲染的。
要實現在裏面放東西,並且還能夠渲染到子組件的相應位置,我們就需要用到“插槽”這個東西。在子組件需要渲染的地方加上一個插槽,就可以引導着雙葉之間的內容渲染到相應的部位了。例如,我們在子組件中可以這樣定義:
1 | <!--Child.vue--> |
然後在父組件中就可以在雙葉之間添加內容了:
1 | <!--Father.vue--> |
<slot></slot>
關鍵字即爲插槽的標誌,代表着父組件雙葉之間的內容將被替換到這裏。上述內容渲染之後是這樣的:
1 | <div id="nihao"> |
可以看到,雙葉之間的內容被替換到了子組件中<slot></slot>
的位置。
至於多插槽的配置,還請讀者自行查閱Vue官方文檔,文檔的內容很好理解。
重要的內置組件
在Vue框架中,有幾個組件是Vue官方幫我們寫好的,我們可以直接使用去實現相應的功能。下面筆者將介紹其中兩個使用比較廣泛的組件。
Transition
<Transition>
會在一個元素或元件進入和離開 DOM 時套用動畫。
進入或離開可以由以下的條件之一觸發:
- 由 v-if 觸發的切換
- 由 v-show 觸發的切換
- 由特殊元素
<component>
切換的動態元件 - 改變特殊的 key 屬性
其中,前兩項是我們比較常用的,第三項將在下一個內置組件中詳細介紹,最後一項不是很常見。
下面是官方文檔中提供給我們的用法案例:
1 | <button @click="show = !show">Toggle</button> |
1 | /* 下面我们会解释这些 class 是做什么的 */ |
下面我們來解釋一下這些CSS動畫效果的實現。
總共有 6 個應用於進入與離開過渡效果的 CSS class。
上面這張圖片很好地展示了這個過程。因此,我們就可以在CSS中,將這些狀態或過程的CSS樣式都定義出來,這樣Transition組件就會幫我們實現這個過渡的過程。
這是官方文檔的解釋:
v-enter-from
:進入動畫的起始狀態。 在元素插入之前添加,在元素插入完成後的下一幀移除。v-enter-active
:進入動畫的生效狀態。 應用於整個進入動畫階段。 在元素插入之前添加,在過渡或動畫完成之後移除。 這個 class 可以用來定義進入動畫的持續時間、延遲與速度曲線類型。v-enter-to
:進入動畫的結束狀態。 在元素插入完成後的下一幀被添加 (也就是 v-enter-from 被移除的同時),在過渡或動畫完成之後移除。v-leave-from
:離開動畫的起始狀態。 在離開過渡效果被觸發時立即添加,在一幀後被移除。v-leave-active
:離開動畫的生效狀態。 應用於整個離開動畫階段。 在離開過渡效果被觸發時立即添加,在過渡或動畫完成之後移除。 這個 class 可以用來定義離開動畫的持續時間、延遲與速度曲線類型。v-leave-to
:離開動畫的結束狀態。 在一個離開動畫被觸發後的下一幀被添加 (也就是 v-leave-from 被移除的同時),在過渡或動畫完成之後移除。
爲過渡效果命名
上面我們套用的動畫,包括我們寫的CSS,是沒有命名的。如果我們有好幾個需要套用不同動畫的元素,這顯然是不夠的。因此,我們可以把每一個動畫效果命名,然後選擇每一個需要套用動畫的元素使用哪一個動畫效果。
例如,我們需要名叫“fade”的一套動畫,我們首先要在CSS中,把前面的效果class改成:
1 | .fade-enter-active, |
可以看到,僅僅只是把默認的“v”換成了需要命名的名字而已。
然後,我們可以在<Transition>
組件的name屬性去套用這個命名:
1 | <Transition name="fade"> |
KeepAlive
要明白這個組件的用處,我們首先要引入動態組件的概念。有些情況下,我們會需要在兩個組件之間互相切換,比如標籤頁。
在這種情況下,我們可以使用<component>
標籤來代替不同的組件:
1 | <component :is="activeComponent" /> |
其中,activeComponent是一個JS變數,其值是已經引入的子組件的名字或者組件實例。
預設情況下,一個元件實例在被替換掉後會被銷毀。 這會導致它遺失其中所有已變更的狀態-當這個元件再一次被顯示時,會建立一個只帶有初始狀態的新實例。
在切換時建立新的元件實例通常是有意義的,但有些時候,我們的確想要元件能在被「切走」的時候保留它們的狀態。 要解決這個問題,我們可以用 <KeepAlive>
內建元件將這些動態元件包裝起來:
1 | <KeepAlive> |
組件庫
組件是功能的集合體,而許許多多這樣的組件放到一起,就形成了組件庫。Vue 3有大量的第三方組件庫,包含了許許多多可以使用的組件。這些組件庫極大拓展了Vue 3的能力。
國內目前比較流行的組件庫是Element Plus。