一, 什么是 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 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 app17 = new Vue({
- el: '#app17'
- });
渲染结果为:
- <div id="app17">
- <div class="container">
- <div class="header">
- <h3> 标题 </h3></div>
- <div class="main">
- <p> 正文内容 </p>
- <p> 更多正文内容 </p>
- </div>
- <div class="footer">
- <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 class="container"><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 .
来源: https://www.cnblogs.com/chaixiaozhi/p/8747967.html