为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个处理称为内容分发,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>
请查看效果:https://codepen.io/riafan/pen/JLRgNd。
可以看出,第一个标签有一段分发内容<div>This is the body</div>
,渲染组件时显示了这段内容。第二个标签则没有,渲染组件时则显示了slot标签中的备用内容。这是因为最初在标签中的任何内容都被视为备用内容。备用内容在子组件的作用域内编译,并且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
二、指定名称的slot
上面这个示例是一个匿名slot,它只能表示一个插槽。如果需要多个内容插槽,则可以为slot元素指定name属性。多个slot一起使用时,会非常有用。例如,对话框是HTML常用的一种交互方式。在不同的运用场景下,对话框的头部、主体内容、底部可能是不一样的。
例如,假定我们有一个modal组件,它的模板为:
<script type="x/template" id="modal-template"> <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> </script>
父组件模板:
<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>
请查看效果:https://codepen.io/riafan/pen/JLRgNd。
指定名称的slot,仍然可以有一个匿名插槽,它是默认插槽,作为找不到匹配的内容片段的备用插槽。如果没有默认插槽,这些找不到匹配的内容片段将被抛弃。模态框底部的插槽就是这样的插槽。通过插槽,可以在子组件中使用自定义内容来覆盖父组件中默认内容,从而大大提高了组件的可重用性。
参考资源: https://v1.vuejs.org/guide/components.html#Compilation-Scope