一、什麼是slot
在使用組件時,我們常常要像這樣組合它們:
<app><app-header></app-header><app-footer></app-footer></app>
當需要讓組件組合使用,混合父組件的內容與子組件的模板時,就會用到slot , 這個過程叫作內容分發( transclusion )。
注意兩點:
1.< app>組件不知道它的掛載點會有什麼內容。掛載點的內容是由<app >的父組件決定的。
2.<app> 組件很可能有它自己的模板。
props 傳遞數據、events 觸發事件和slot 內容分發就構成了Vue 組件的3 個API 來源,再複雜的組件也是由這3 部分構成的。
二、作用域
<child-component>{{ message }}</child-component>
這裡的message 就是一個slot ,但是它綁定的是父組件的數據,而不是組件<child-component>的數據。
父組件模板的內容是在父組件作用域內編譯,子組件模板的內容是在子組件作用域內編譯。如:
<div id="app15"><child-component v-show="showChild"></child-component></div>Vue.component('child-component',{template: '<div>子組件</div>'});var app15 = new Vue({el: '#app15',data: {showChild: true}});
這裡的狀態showChild 綁定的是父組件的數據,如果想在子組件上綁定,那應該是:
<div id="app15"><child-component></child-component></div>Vue.component('child-component',{template: '<div v-show="showChild">子組件</div>',data: function(){return {showChild: true}}});
因此, slot 分發的內容,作用域是在父組件上的。
三、slot用法
3.1 單個slot
在子組件內使用特殊的<slot>元素就可以為這個子組件開啟一個slot(插槽),在父組件模板裡,插入在子組件標籤內的所有內容將替代子組件的<slot> 標籤及它的內容。
<div id="app16"><my-component16><p>分發的內容</p><p>更多分發的內容</p></my-component16></div>Vue.component('my-component16',{template: '<div>' +'<slot><p>如果父組件沒有插入內容,我將作為默認出現<</p></slot>' + //預留的slot插槽'</div>'});var app16 = new Vue({el: '#app16'});
渲染結果為:
<div id=」app16」><div><p>分發的內容<p><p>更多分發的內容<p></div></div>
子組件child-component 的模板內定義了一個<slot>元素,並且用一個<p>作為默認的內容,在父組件沒有使用slot 時,會渲染這段默認的文本;如果寫入了slot, 那就會替換整個<slot> 。
3.2具名slot
給<slot> 元素指定一個name 後可以分發多個內容,具名Slot 可以與單個slot 共存。
<div id="app17"><my-component17><h3 slot="header">標題</h3><p>正文內容</p><p>更多正文內容</p><h3 slot="footer">底部信息</h3></my-component17></div>Vue.component('my-component17',{template: '<div>' +'<div>' +'<slot name="header"></slot>' +'</div>' +'<div>' +'<slot></slot>' +'</div>'+'<div>' +'<slot name="footer"></slot>' +'</div>'+'</div>'});var app17 = new Vue({el: '#app17'});
渲染結果為:
<div id="app17"><div><div><h3>標題</h3></div><div><p>正文內容</p><p>更多正文內容</p></div><div><h3>底部信息</h3></div></div></div>
子組件內聲明了3 個<s lot>元素,其中在<div class=」 main >內的<slot> 沒有使用name 特性,它將作為默認slot 出現,父組件沒有使用slot 特性的元素與內容都將出現在這裡。
如果沒有指定默認的匿名slot ,父組件內多餘的內容片段都將被拋棄。
四、作用域插槽
作用域插槽是一種特殊的slot ,使用一個可以復用的模板替換己渲染元素。
看一個例子:
<div id="app18"><my-component18><template scope="props"><p>來自父組件的內容</p><p>{{props.msg}}</p></template></my-component18></div>Vue.component('my-component18',{template: '<div><slot msg="來自子組件的內容"></slot></div>'});var app18 = new Vue({el: '#app18'});
渲染結果為:
<div id=」app18」><div class=」container」><p>來組父組件的內容</p><p>來自子組件的內容</p></div></div>
觀察子組件的模板,在<slot>元素上有一個類似props 傳遞數據給組件的寫法msg=」 xxx 」,將數據傳到了插槽。
父組件中使用了<template>元素,而且擁有一個scope=」props 」的特性,這裡的props只是一個臨時變量,就像v-for= 」 item in items 裡面的item 一樣,template 內可以通過臨時變量props訪問來自子組件插槽的數據msg 。