为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个处理称为内容分发,Vue.js 实现了一个内容分发 API,使用特殊的元素作为原始内容的插槽。如果你是 AngularJS 用户,slot 就和的“transclude”差不多。
一、单个 Slot
当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片段将插入到插槽所在的 DOM 位置,并替换掉插槽标签本身。
假定 my-component
组件有如下模板:
<div id="app">
<my-component>
<div>This is the body</div>
</my-component>
<hr/>
<my-component></my-component>
</div>
父组件模板:
<template id="myComponent">
<h3>This is the title</h3>
<div class="content">
<slot>This is the fallback content.</slot>
<div>This is the footer.</div>
</div>
</template>
可以看出,第一个标签有一段分发内容 <div>This is the body</div>
,渲染组件时显示了这段内容。第二个标签则没有,渲染组件时则显示了 slot 标签中的备用内容。这是因为最初在标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
二、指定名称的 slot
上面这个示例是一个匿名 slot,它只能表示一个插槽。如果需要多个内容插槽,则可以为 slot
元素指定 name
属性。多个 slot 一起使用时,会非常有用。例如,对话框是 HTML 常用的一种交互方式。在不同的运用场景下,对话框的头部、主体内容、底部可能是不一样的。
例如,假定我们有一个 modal 组件,它的模板为:
<div class="modal-mask" v-if="shown" transition="modal">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header" name="header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
default body
</slot>
</div>
<div class="modal-footer">
<slot>
<button class="btn default-button"
@click="shown=false">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
父组件模板:
<div id="app">
<button class="btn btn-open" id="show-modal" @click="showModal=true">Show Modal</button>
<modal :shown.sync="showModal">
<div slot="header">
<div class="modal-title">
Put title here
</div>
<div class="icon-close" @click="showModal=false">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path>
</svg>
</div>
</div>
<div slot="body">
<p>Please put some content here</p>
</div>
</modal>
</div>
查看效果
访问 Codepen 查看代码及最终效果。
指定名称的 slot,仍然可以有一个匿名插槽,它是默认插槽,作为找不到匹配的内容片段的备用插槽。如果没有默认插槽,这些找不到匹配的内容片段将被抛弃。模态框底部的插槽就是这样的插槽。通过插槽,可以在子组件中使用自定义内容来覆盖父组件中默认内容,从而大大提高了组件的可重用性。
评论 (0)