Vue – 如何理解「使用 slot 分發內容」
關於 slot (插槽) 的範例說明,在官方網站並不是介紹得很清楚(參考)。標題「使用 slot 分發內容」這句話其實不易理解,但意思就是說「父組件準備好內容,分發給子組件安排的結構」。父組件只負責內容,但不負責擺放的位置;子組件負責擺放位置,但不理會內容是什麼。
- 內容就是長相
- 例如你要呈現的 <header><main><div>文字…長怎麼樣
- 像是眼睛會有眼睫毛、眼皮、眼珠子。
- 當然也可以把眼睛再拆分更細的組件,就看需求了。
- 結構就是擺哪裡
- 例如你的 <header> 要把在 <main> 的前面或後面?
- 像是眼睛要擺在鼻子上方,嘴要放在鼻子下方。
這裡我依序擴增的步驟來教學。
步驟一、建立 Vue 初始位置,並加入組件
1 2 3 |
<div class="app"></div> |
1 2 3 4 5 |
new Vue({ el: '.app' }) |
步驟二、加入父組件
加入 <c-container> 組件,告知使用 #element 模板
1 2 3 4 5 6 7 8 9 |
<!-- 父模板,用來準備內容 --> <template id="element"></template> <div class="app"> <!-- 決定組件要擺放的位置 --> <c-container></c-container> </div> |
1 2 3 4 5 6 7 8 9 10 |
// 父組件 Vue.component('c-container', { template: '#element' }) new Vue({ el: '.app' }) |
步驟三、在父模版中,用子組件包圍內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<template id="element"> <!-- 用子組件標籤,包圍要呈現的內容,目前只有 header --> <c-struct> <header> <h1>Header</h1> </header> </c-struct> </template> <div class="app"> <c-container></c-container> </div> |
這時候會輸出
1 2 3 4 5 6 7 8 9 |
<div class="app"> <c-struct> <header> <h1>Header</h1> </header> </c-struct> </div> |
目前有 <c-struct> 是因為我們還沒有指派子組件。
步驟四、加入子組件
- <c-struct> 組件,告知使用 #container 模板
- 指定 header 對應插槽(slot)的名稱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!-- 子組件使用的模版 --> <template id="container"> </template> <template id="element"> <c-struct> <!-- 指定等會 header 對應插槽(slot)的名稱 --> <header slot="header"> <h1>Header</h1> </header> </c-struct> </template> <div class="app"> <c-container></c-container> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// 子組件 Vue.component('c-struct', { template: '#container' }) Vue.component('c-container', { template: '#element' }) new Vue({ el: '.app' }) |
因為設定了子組件 c-struct,所以目前存檔的畫面會變空白。因為模版 #container 我們還沒有寫內容,template#element > c-struct 會被丟棄。
步驟五、子組件加入 <slot> 擺放位置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<template id="container"> <!-- .container 會替換父組件 <c-struct> 的位置 --> <div class="container"> <!-- slot 指定名稱 header,所以這個位置被父元素 <header> 替換 --> <slot name="header"></slot> </div> </template> <template id="element"> <c-struct> <header slot="header"> <h1>Header</h1> </header> </c-struct> </template> <div class="app"> <c-container></c-container> </div> |
會輸出
1 2 3 4 5 6 7 8 9 |
<div class="app"> <div class="container"> <header> <h1>Header</h1> </header> </div> </div> |
我們會發現 .container出現了,.container 底下也將 <slot name=”header”> 替換為 <heade>。
步驟六、添加其他 slot 插槽位置與對應內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
<template id="container"> <div class="container"> <slot name="header"></slot> <!-- 放置插槽 main --> <slot name="main"></slot> <!-- 放置插槽 footer 在 插槽 main 之後 --> <slot name="footer"></slot> </div> </template> <template id="element"> <c-struct> <header slot="header"> <h1>Header</h1> </header> <!-- 加入 footer --> <footer slot="footer"> <p>Footer</p> </footer> <!-- 加入 main --> <main slot="main"> <article> <p>Say</p> <p>Hello</p> </article> </main> </c-struct> </template> <div class="app"> <c-container></c-container> </div> |
會輸出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<div class="app"> <div class="container"> <header> <h1>Header</h1> </header> <!-- 先出現 main --> <main> <article> <p>Say</p> <p>Hello</p> </article> </main> <!-- 再出現 footer --> <footer> <p>Footer</p> </footer> </div> </div> |
為什麼會先出現 <main> 再出現 <footer> 呢?因為我們在子組件 (c-struct) 指定的模版 (template#container) ,插槽依序排列為 <slot name=”header”>、<slot name=”main”>、<slot name=”footer”>。所以一旦我們改變 <slot> 的位置,呈現的順序也就跟著不同囉。
如果不指定 <slot> 的 name 會怎麼樣?
若子組件的模版只有 <slot>,那就會把父組件模版中沒有指定 slot 屬性的元素,收集起來,替換掉 <slot> 的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
<template id="container"> <div class="container"> <slot name="header"></slot> <!-- 這裡改成沒有 name 屬性的 slot --> <slot></slot> <slot name="footer"></slot> </div> </template> <template id="element"> <c-struct> <!-- 加入沒指定 slot 的內容 --> <menu>散落的內容 1</menu> <header slot="header"> <h1>Header</h1> </header> <!-- 加入沒指定 slot 的內容 --> <p>散落的內容 2</p> <footer slot="footer"> <p>Footer</p> </footer> <!-- 加入沒指定 slot 的內容 --> <ul> <li>散落的內容 3</li> <li>散落的內容 4</li> </ul> </c-struct> </template> <div class="app"> <c-container></c-container> </div> |
會輸出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<div class="app"> <div class="container"> <header> <h1>Header</h1> </header> <menu>散落的內容 1</menu> <p>散落的內容 2</p> <ul> <li>散落的內容 3</li> <li>散落的內容 4</li> </ul> <footer> <p>Footer</p> </footer> </div> </div> |
如果有散落的元素內容,但子組件模版中沒有 <slot> 會如何?
1 2 3 4 5 6 7 8 9 |
<template id="container"> <div class="container"> <slot name="header"></slot> <!-- 改成沒有 slot --> <slot name="footer"></slot> </div> </template> |
那內容就會被丟棄,不會顯示囉!會輸出
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="app"> <div class="container"> <header> <h1>Header</h1> </header> <footer> <p>Footer</p> </footer> </div> </div> |
zhang hongyu
2020-07-17 - 15:01
講解的很好