作用域插槽
作用域插槽是一种特殊的slot,使用一个可以复用的模板替换已渲染元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<title>作用域插槽</title>
</head>
<body>
<div id="app">
<child-component>
<template scope="props">
<p>来自父组件的内容</p>
<p>{{props.msg}}</p>
</template>
</child-component>
</div>
<script>
Vue.component('child-component',{
template: '\
<div class="container">\
<slot msg="来自组件的内容"></slot>\
</div>'
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
在< slot >元素上有一个类似props传递数据给组件的写法msg=“xxx”,将数据传到了插槽。父组件中使用了< template >元素,而且拥有一个scope=“props"的特性,这里的props只是一个临时变量,就像v-for=”item in items“里面的item一样。template内可以通过临时变量props访问来自组件插槽的数据msg。
上面的例子最终渲染结果为:
<div id="app">
<div class="container">
<p>来自父组件的内容</p>
<p>来自子组件的内容</p>
</div>
</div>
作用域插槽更具代表性的用例是列表组件,允许组件自定义应该如何渲染列表每一项:
<div id="myApp">
<my-list :books="books">
<!--作用域插槽也可以是具名的slot-->
<template slot="book" 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内容-->\
</slot>\
</ul>'
});
var myApp = new Vue({
el: '#myApp',
data: {
books: [
{name: 'C'},
{name: 'C++'},
{name: 'Java'}
]
}
});
</script>
子组件my-list接收一个来自父级的props数组books,并且将它再name为book的slot上使用v-for循环,同时暴露一个变量bookName。
访问slot
Vue.js 2.x提供了用来访问被slot分发的内容的方法 $slots 。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<title>访问slot</title>
</head>
<body>
<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);
//console.log(footer[0].elm.innerHTML);
}
});
var app = new Vue({
el: '#app'
});
</script>
</body>
</html>
通过$slots可以访问某个具名slot, this.$slots.default包括了所有没有被包含在具名slot中的节点。