先前Day 18中提到父組件可以通過props
將參數資料傳遞給子組件進行渲染,這樣可以有效地將資料處理與畫面渲染的工作分開。然而,當我們需要更加客製化的呈現內容,由父組件來控制子組件的部分顯示時,可以使用v-slot 指令
,將父組件的模板
傳入給子組件,可以更靈活地呈現內容。
以下透過一個父組件傳入按鈕模板內容
給子組件的案例進行說明:
👉 Vue3 Options API slot 默認插槽內容實作連結
流程說明:
slot
標籤接應父組件要傳入的模板內容。父組件 Vue Template:
<div id="app">
<fancy-button>
<button type="button">{{ icon }} {{ buttonText }}</button>
</fancy-button>
</div>
父組件 javascript:
const rootComponent = {
data() {
return {
buttonText: "我是按鈕",
icon: "🐱"
};
},
components: { FancyButton }
};
子組件 Vue Template:
<slot>
<p>目前暫時不服務!</p>
</slot>
⭐ 子組件的slot
標籤裡面可以放置預設值,當父組件未傳入模板內容的時候就會套用<p>目前暫時不服務!</p>
。若父組件有傳入模板內容,則會忽略slot
標籤裡面的內容。
這邊附上父組件透過props
傳入資料,子組件根據資料渲染的案例,讓大家感受一下兩者架構的差異,也可以思考一下再擴增功能上的方向。
👉 Vue3 Options API 父組件傳遞 props 資料給子組件實作連結
子組件使用的slot
標籤可以設定不只一個,當使用複數個slot
標籤的時候,父組件需要搭配具名插槽加上template
標籤使用,才可以明確配對子組件中每個slot
標籤要寫入對應的template
是哪一個。
在說明v-slot
縮寫之前,幫大家複習一下之前常用指令的縮寫:
:
@
#
以下透過子組件制定網頁版型,並由父組件根據不同區塊傳入模板內容案例說明:
👉 Vue3 Options API slot 具名插槽實作連結
流程說明:
header
、main
及footer
標籤區域。template name
與具名插槽名稱的對應,使彼此內容互不影響。父組件 Vue Template:
<div id="app">
<base-layout>
<template v-slot:header>
<h2>這是 header</h2>
</template>
<template #main>
<h2>這是 main</h2>
</template>
<template #footer>
<h2>這是 footer</h2>
</template>
</base-layout>
</div>
子組件 Vue Template
<template id="child">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</template>
如果slot
標籤未設置名稱,或者使用了預設名稱default
,那麼所有無法對應到具名插槽的模板內容都會被放置在這個插槽中。可以將slot
標籤想像成一個分類器,負責將父組件傳入的模板內容進行分類。
延續上面的案例,我們試著透過範例更加了解:
👉 Vue3 Options API slot 未命名內容插槽與具名插槽的使用實作連結
父組件 Vue Template:
<div id="app">
<base-layout>
<template v-slot:header>
<h2>這是 header</h2>
</template>
<template #main>
<h2>這是 main</h2>
</template>
<template #footer>
<h2>這是 footer</h2>
</template>
<div #test1122334455>123</div>
<p>我是剩餘段落</p>
</base-layout>
</div>
子組件 Vue Template:
<template id="child">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="main"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
<div class="container">
<h2>未命名插槽內容(預設插槽)</h2>
<slot></slot>
<h2>具名的預設插槽內容(插槽名稱為 "default")</h2>
<slot name="default"></slot>
</div>
</template>
在這裡可以看到,使用#test1122334455
這個具名插槽,但在子組件中沒有對應的插槽,因此其內容會自動放置到未命名的<slot></slot>
或具名為default
的插槽中。
一般來說,使用slot
插槽時,父組件會傳遞模板內容給子組件來進行渲染。然而,在某些情況下,我們可能希望部分數據的控管在子組件中進行,並將這些參數回傳給父組件,使父組件能根據這些參數動態改變傳入的模板內容。這時,我們會使用作用域插槽
,使子組件能將必要的參數提供給父組件使用。
此外,根據是否使用具名插槽,插槽的使用方式會有所不同。以下將分別舉例,幫助大家更好地理解作用域插槽的應用。
<my-component v-slot="slotProps">
)👉 Vue3 Options API 子組件默認內容插槽傳遞參數實作連結
父組件 Vue Template:
<div id="app">
<my-component v-slot="slotProps">
<p>slotProps:{{ slotProps }}</p>
<p>text:{{ slotProps.text }}</p>
<p>count:{{ slotProps.count }}</p>
</my-component>
<p>子組件外部範圍 slotProps:{{ slotProps }}</p>
</div>
⭐ 子組件通過v-slot
傳遞的slotProps
參數只能在父組件中引用插槽內容的區域內使用,而不能在父組件的外部範圍使用。
子組件 Vue Template:
<template id="child">
<slot :text="text" :count="count"></slot>
</template>
<template>
,否則參數無法正確傳遞與使用。在傳遞參數時,具名插槽會將其對應於特定的<template>
,而且這些參數的作用域僅限於對應的<template>
標籤內。👉 Vue3 Options API slot 具名插槽傳值實作連結
父組件 Vue Template:
<div id="app">
<base-layout>
<template #header="slotProps">
<h2>這是 header</h2>
<p>查看子組件傳入的參數值:{{ slotProps }}</p>
</template>
<template #main="slotProps">
<h2>這是 main</h2>
<p>查看子組件傳入的參數值:{{ slotProps }}</p>
</template>
<template #footer="slotProps">
<h2>這是 footer</h2>
<p>查看子組件傳入的參數值:{{ slotProps }}</p>
</template>
</base-layout>
</div>
子組件 Vue Template:
<template id="child">
<header>
<slot name="header" :headeMessage="headeMessage"></slot>
</header>
<main>
<slot name="main" :mainMessage="mainMessage"></slot>
</main>
<footer>
<slot name="footer" :footerMessage="footerMessage"></slot>
</footer>
</template>
在混合上面預設內容插槽傳遞參數
及具名插槽傳遞參數
的情況下,預設插槽的內容需要在父組件中使用具名為default
的<template>
才能正常編譯和顯示。
👉 Vue3 Options API slot 具名插槽 + 默認內容插槽傳值實作連結
這裡我們以一個常見的模板類型為例,演示如何將內容以「列表式」或「卡片式」兩種方式進行呈現。我們將以 momo 官方網站為範例,並對比使用props
和slot
的組件設計思維,展示不同的實現方式。
【 momo 官網查詢 - 卡片式呈現搜尋結果 】
【 momo 官網查詢 - 列表式呈現搜尋結果 】
showType props
決定呈現類型的組件。👉 Vue3 Options API 不同排版方式 porps 參數設計方式實作連結
slot
回傳的參數提供。slot
將參數回傳給父組件使用。👉 Vue3 Options API 不同排版方式 slot 參數設計方式實作連結
兩種方式都能實現相同的功能,主要差異在於當顯示類型需要增加時(例如:新增 grid「四列網格」項目組件),兩種設計方式的修改如下:
showType
中新增第三種類型grid
。showType
選項grid
。showType
中新增第三種類型grid
。showType
選項grid
。模板內容
。在這個場景案例中,使用props
設計方式時,如果需要新增顯示類型,父組件和子組件都需要進行相應的調整。而使用slot
設計方式時,子組件的職責更加單一,只負責處理API
資料的讀取,因此僅需在父組件中進行修改,讓維護和擴展更為方便。
在以下示例中,子組件的模板可以使用$slots
配合條件語句來判斷插槽是否存在。如果插槽存在,則顯示父組件傳入的模板內容;如果插槽不存在,則顯示一條提示信息:<h2>父組件尚未提供 v-slot 綁定 content</h2>
。此外,也可以在mounted
生命週期階段通過console.log(this.$slots)
來查看當前傳入的具名插槽。
👉 Vue3 Options API slot 條件渲染實作連結
父組件 Vue Template:
<div id="app">
<child-component>
<template #content>
hello world vue !
</template>
</child-component>
</div>
子組件 Vue Template:
<template id="childComponent">
<div v-if="$slots.content" class="content">
<h2>
<slot name="content"></slot>
</h2>
</div>
<div v-else class="default">
<h2>父組件尚未提供 v-slot 綁定 content</h2>
</div>
</template>
v-bind
可以用來設置動態屬性名稱,而v-slot
同樣可以綁定動態插槽名稱,從而更靈活地控制插槽的內容。
透過以下案例進行流程說明:
v-model
綁定blocktype
響應式變數👉 Vue3 Options API slot 動態插槽實作連結
父組件 Vue Template:
<div id="app">
<div class="input-group">
<label for="blockOption">選擇 slot 插槽名稱:</label>
<select name="blockOption" id="blockOption" v-model="blocktype">
<option disabled value="">請選擇</option>
<option value="header">header</option>
<option value="body">body</option>
<option value="footer">footer</option>
</select>
</div>
<div class="content">
<child-component>
<template #[blocktype]>
<h2>今天開心嗎!!!!!(動態小壞蛋) 顯示 blocktype:{{ blocktype }}</h2>
</template>
</child-component>
</div>
</div>
子組件 Vue Template:
<template id="childComponent">
<div>我是childComponent!!</div>
<slot name="header">
<h2>我是預設 header</h2>
</slot>
<slot name="body">
<h2>我是預設 body</h2>
</slot>
<slot name="footer">
<h2>我是預設 footer</h2>
</slot>
</template>
預設內容插槽
可用來顯示父組件未傳入模板時的預設內容,具名插槽
則需要父組件可以精確地指定要插入的內容位置。子組件
可以透過作用域插槽
將其內部管理的參數回傳給父組件,從而使父組件能夠根據這些參數動態地改變顯示的模板內容。需要注意的是,具名插槽
與預設內容插槽
在傳遞變數的位置上有所不同,這樣可以確保父組件中的對應模板能接收到來自特定作用域的參數。$slots
搭配條件語句來判斷插槽是否存在,從而根據情況顯示不同的內容。v-slot
可以綁定動態的插槽名稱,使得父組件能夠根據響應式變數
動態決定要渲染哪個插槽,達到更靈活的插槽內容控制。slot
是我學習Vue
的過程中,認為最難理解的部分。一度跳過這個部分,這次也好好的把整個內容跑過一次,我並不聰明,但我始終相信這過程中所有的練習都會變成我的養分。
這次提供的練習是結合props
及slot
的應用(僅需調整模板上slot
參數傳遞的部分):
流程說明:
currentLang
傳遞給子組件slot 參數
回傳要顯示的內容slot 參數
內容後,組成對應模板傳遞給子組件顯示👉 Vue3 Options API props 搭配 slot 結合使用練習模板
👉 Vue3 Options API props 搭配 slot 結合使用完成版本