當需要讓組件組合使用,混合父組件的內容與子組件的模板時,就會用到slot,這個過程叫做內容分發。
1、slot內容分發
在子組件內使用特殊的<slot>元素就可以爲這個子組件開啓一個slot(插槽),在父組件模板裏,插入在子組件標籤內的所有內容將替代子組件的<slot>標籤及它的內容。例如:
<div id="app">
<child-component>
<div>分發的內容</div>
<p>更多分發的內容</p>
</child-component>
<!-- 子組件裏沒有內容時,顯示slot裏面的內容 -->
<child-component></child-component>
</div>
<script>
/* slot 當子組件沒有內容的時候顯示(備用內容) */
Vue.component('child-component',{
template: '<div>\
<slot>如果父組件裏的子組件標籤裏沒有插入內容,我將作爲默認出現</slot>\
</div>',
data: function(){
return {
name: '子組件的數據;'
}
}
});
var app = new Vue({
el: '#app'
});
</script>
沒有name屬性的slot將作爲默認slot出現,父組件沒有使用slot特性的元素與內容都將出現在這裏;如果沒有指定默認的匿名slot,父組件內多餘的內容片段都將被拋棄。例如:
<div id="app">
<child-component>
<h2 slot="header">標題</h2>
<p>正文內容</p>
<p>更多的正文內容</p>
<div slot="footer">底部信息</div>
</child-component>
</div>
<script>
Vue.component('child-component',{
template: `
<div class="container">
<div class="header">
<slot name="header"></slot>
</div>
<div class="main">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
`
});
var app = new Vue({
el: '#app'
});
</script>
以上代碼中,類名爲main的div裏面的slot沒有name屬性,是默認的slot,顯示的內容正是子組件child-component裏的兩個沒有slot屬性的p標籤裏面的內容;子組件<slot>內的備用內容,它的作用域是子組件本身。
2、作用域插槽
作用域插槽是一種特殊的slot,使用一個可以複用的模板替換已渲染元素。例如:
<div id="app">
<child-component>
<!-- 臨時變量props,用於訪問來自子組件插槽的數據msg -->
<template slot-scope="props">
<p>來自父組件的內容</p>
<p>{{ props.msg }}</p>
</template>
</child-component>
</div>
<script>
/*
沒有name的slot將作爲默認slot出現,父組件沒有使用slot特性的元素與內容都將
出現在這裏;如果沒有指定默認的匿名slot,父組件內多餘的內容片段都將被拋棄
*
* */
Vue.component('child-component',{
template: `
<div class="container">
<slot msg="來自子組件的內容"></slot>
</div>
`
});
var app = new Vue({
el: '#app'
});
</script>
作用域插槽更具代表性的用例是列表組件;允許組件自定義應該如何渲染列表每一項。例如:
<div id="app">
<my-list :books="books">
<!-- 作用域插槽也可以是具名的slot -->
<template slot="book" slot-scope="props">
<li>{{ props.bookName }}</li>
</template>
</my-list>
</div>
<script>
Vue.component('my-list', {
props: {
books: {
type: Array,
default: function () {
return [];
}
}
},
template: `
<ul>
<slot name="book" v-for="book in books" :book-name="book.name">
</slot>
</ul>
`
});
var app = new Vue({
el: '#app',
data: {
books: [
{name: '《vue.js實戰》'},
{name: '《javascript語言精粹》'},
{name: '《javascript高級程序設計》'}
]
}
});
</script>
3、訪問slot
通過$slot可以訪問某個具名slot,this.$slots.default包括了所有沒有被包含在具名slot中的節點。例如:
<div id="app">
<child-component>
<h2 slot="header">標題</h2>
<p>正文內容</p>
<p>更多正文內容</p>
<div slot="footer">底部信息</div>
</child-component>
</div>
<script>
Vue.component('child-component', {
template: `
<div class="container">
<div class="header">
<slot name="header"></slot>
</div>
<div class="main">
<slot></slot>
</div>
<div class="footer">
<slot name="footer"></slot>
</div>
</div>
`,
mounted: function () {
var header = this.$slots.header;
var main = this.$slots.default;
var footer = this.$slots.footer;
console.log(footer); // 打印出footer元素的虛擬dom對象
console.log(footer[0].elm.innerHTML); // "底部信息"
}
});
var app = new Vue({
el: '#app'
});
</script>