当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到
slot
。这个过程叫做内容分发。
其主要特点为:
- 子组件不知道它的挂载点会有什么内容,挂载点的内容是由其父组件决定的。
- 子组件有自己的模板。
1. 作用域
首先需要了解一个概念: 编译的作用域。
父组件模板的内容是在父组件作用域内编译,子组件模板的内容是在子组件作用域内编译。
slot
分发的内容,作用域是在父组件上的。
2. slot用法
在子组件内使用<slot>
元素就可以为这个子组件开启一个slot
插槽,在父组件模板中,插入在子组件标签内的所有内容将代替子组件的<slot>
标签及它的内容:
单个slot
<!-- 单个slot -->
<body>
<div id="app">
<child-component>
<p>分发的内容</p>
<p>更多分发的内容</p>
</child-component>
</div>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
Vue.component('child-component',{
template: '\
<div>\
<slot>\
<p>如果父组件没有插入内容,我将默认出现</p>\
</slot>\
</div>'
});
var app = new Vue({
el: '#app',
})
</script>
</body>
执行结果
如果将上述代码中的这部分注释:
<child-component>
<!-- <p>分发的内容</p>
<p>更多分发的内容</p> -->
</child-component>
则执行结果如下:
执行结果可见,在父组件没有使用slot
时,会渲染子组件的默认文本;如果写入了slot
将会替换整个<slot>
。
具名slot
为<slot>
元素指定一个name
后可以分发多个内容,剧名Slot可以与单个Slot共存:
<!-- 具名slot -->
<body>
<div id="app">
<child-component>
<h2 slot="header">覆盖标题</h2>
<div slot="footer">覆盖底部</div>
</child-component>
</div>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
<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>
</body>
执行结果
子组件中声明了三个<slot>
,其中<div class="main">
中的<slot>
没有使用name
属性,即为默认slot
,如果父组件包含没有使用slot
特性的元素都将出现在这里。
3. 作用域插槽
作用域插槽是一种特殊的slot,其使用一个可以复用的模板替换已渲染元素。
<!-- 作用域插槽 -->
<body>
<div id="app">
<child-component>
<template scope="props">
<p>来自父组件的内容</p>
<p>{{props.msg}}</p>
</template>
</child-component>
</div>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
<script>
Vue.component('child-component',{
template: '\
<div class="container">\
<slot msg="来自子组件的内容"></slot>\
</div>'
});
var app = new Vue({
el: '#app',
})
</script>
</body>
执行结果
上述代码在子组件的模板上,<slot>
元素中有一个类似props
传递数据给组件的写法msg="xxx"
,将数据传到了插槽。父组件中使用<template>
模板,并且拥有一个scope="props"
的特性,这里的props
只是一个临时变量,template
内可以通过这个临时变量访问来自子组件插槽中的数据msg
。
4.访问slot
Vue 2.x提供了用来访问被slot
分发的内容的方法$slots
:
<!-- 访问slot -->
<body>
<div id="app">
<child-component>
<h2 slot="header">覆盖标题</h2>
<p>覆盖正文</p>
<p>更多覆盖正文</p>
<div slot="footer">覆盖底部</div>
</child-component>
</div>
<script src = "https://unpkg.com/vue/dist/vue.min.js"></script>
<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; //所有没有包含在具名slot中的节点
var footer = this.$slots.footer;
console.log(footer);
console.log(footer[0].elm.innerHTML);
}
});
var app = new Vue({
el: '#app',
})
</script>
</body>
执行结果
通过$slots
可以访问某个具名slot,this.$slots.default
包括了所有没有包含在具名slot中的节点。
参考
- 《Vue.js 实战》
网友评论