Andy's blog

If you always do what you've always done, you'll always get what you've always got.

0%

Vue Component(元件)-slot元件插槽

參考資料


前言

在介紹slot之前,我們必須先瞭解一個觀念:編譯作用域
我們先來看個範例
codepen連結

1
2
3
4
<div id="app">
<div class="parent">{{msg}}</div>
<child>{{msg}}</child>
</div>

猜猜看,child元件中是否會印出父層的msg:I'mparent內容?
答案是不會的!原因是目前child所處的位置是父層作用域,當然不會印出子層內容~

補充:在Vue生命週期中,Vue會在created階段時判斷是否有template,如果有vue則會去編譯template內容,也因此,child元件不會顯示I’mparent內容
https://ithelp.ithome.com.tw/upload/images/20191009/20114645YYilPuEj6G.png

圖示結果:
https://ithelp.ithome.com.tw/upload/images/20191009/20114645DNIetTy2Ci.png

小結論:

1.父層作用域在父層編譯
2.子層作用域在子層編譯
若要突破作用域編譯問題,就要使用到slot


Slot簡介

參考資料:Summer 夏天Vue.js: Slot
突破作用域,將父層內容傳遞進來!通常會應用在如果內容不一定要放入component中時,可以透過slot傳遞一整個html結構進來。

Slot 是一種用於內容分配(Content Distribution / Transclusion)的元件,適用於複雜或巢狀元件的實作上,可以想像成是空間預留的方法,在迭代過程中再把內容塞進去。

卡斯伯老師在課堂上將slot分為三種:
1.沒有slot的狀態

1
2
3
<no-slot-component>
<p>這是一段沒有插槽使用的狀態</p>
</no-slot-component>

說明:即使寫p段落文字在子元件中,在html上依舊不會顯示。因為元件中的內容都會被模板替換掉。這就是上方提到作用域編譯的問題~

2.單組slot
特點:在模板中添加<slot><slot/>
HTML部分

1
2
3
<single-slot-component>
<p>使用這段取代原本的 Slot。</p>
</single-slot-component>

template部分

1
2
3
4
5
6
7
8
<script type="text/x-template" id="singleSlotComponent">
<div class="alert alert-warning">
<h6>我是一個元件</h6>
<slot>
如果沒有內容,則會顯示此段落。
</slot>
</div>
</script>

畫面上,就可以將<p>使用這段取代原本的 Slot。</p>呈現在畫面上!如下
https://ithelp.ithome.com.tw/upload/images/20191009/20114645IWKZBTkNyY.png

3.多組slot(具名插槽)
簡單來說,將內容放入指定位置
寫法:
1.在html加入slot
2.在元件模板插入 name
練習連結
HTML部分

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
<child>
<p>123</p>
<h1 class="header" slot="header">這是 HEADER</h1>

<p>A paragraph for the main content.</p>
<p>And another one.</p>

<p class="footer" slot="footer">這是 FOOTER</p>

</child>

<template id="child-template">
<div class="container">
<header>
<slot name="header">Default Header</slot>
</header>
<hr>

<main>
<slot>Default Body</slot>
</main>

<hr>
<footer>
<slot name="footer">Default Footer</slot>
</footer>
</div>
</template>

補充:html結構中若不想顯示標籤如a、header,可以使用<template>,這樣就不會顯示標籤摟~

練習一下

猜猜看下面這個範例child元件,會印出什麼內容?
練習連結
HTML部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<div class="parent">{{ msg }}</div>
<child>
<div>This "msg" is from parent: {{ msg }}</div>
</child>
</div>

<template id="child-template">
<div class="child">
<div>{{ msg }}</div>
<!-- 預設slot文字 -->
<slot> Default Slot Content </slot>
</div>
</template>

JavaSvript部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// children component
Vue.component('child', {
template: '#child-template',
data: function () {
return {
msg: 'I\'m child.'
};
}
});

// parent component
var parent = new Vue({
el: '#app',
data: {
msg: 'I\'m parent.'
}
});

答案是:
https://ithelp.ithome.com.tw/upload/images/20191009/20114645wwTeKanLW0.png

原因:之所以child中的msg會印出I'm parent字樣,就是因為child所在區域,還是在父層。因此編譯作用域還是在父層內。

後記

在2.6.0中,我們為具名插槽和作用域插槽引入了一個新的統一的語法(即v-slot指令)。它取代了slot和slot-scope