当需要让组件组合使用,混合父组件的内容与子组件的模板时,就会用到sloat,这个过程叫做内容分发。
props传递数据,events触发事件,sloat分发内容,就构成了vue组件的3个API来源。
一、slot的用法
单个slot
在子组件内使用特殊的<slot>元素就可以为这个子组件开启一个slot(插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的<slot>标签及它的内容。
<div id="app"> <child-component> <p>这是分发内容</p> <p>更多的分发内容</p> </child-component> </div> <script type="text/javascript"> Vue.component('child-component',{ props:{}, template:'<div>\ <slot>\ <p>如果父组件没有插入内容,我将作为默认出现</p>\ </slot>\ </div>' }) var app = new Vue({ el: '#app', data: { }, methods:{} }) </script>
子组件child-component 模板内定义了一个<slot>元素,并且用一个<p>作为默认的内容,在父组件没有使用<slot>时,会渲染这段默认的文本,如果父组件写入了<slot>,那父组件的slot会替换整个子组件的<slot>
最终渲染结果为:
<div id="app"> <div> <p>这是分发内容</p> <p>更多的分发内容</p> </div> </div>
注意:子组件内的备用内容,它的作用域是子组件本身
具名slot
给<slot>指定一个name后可以分发多个内容,具名<slot>可以和单个<slot>共存
<div id="app"> <child-component> <h2 slot="header">标题</h2> <p>正文内容</p> <p>更多正文内容</p> <div slot="footer">底部信息</div> </child-component> </div> <script type="text/javascript"> Vue.component('child-component',{ props:{}, 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', data: { }, methods:{} }) </script>
子组件内声明了多个<slot>元素,其中<div class="min">内的<slot>没有使用name特性,它将作为默认的<slot>出现,父组件没有使用<slot>特性的元素与内容将出现在这里
作用域插槽
作用域插槽是一种特殊的<slot>,使用一个可复用的模板替换已渲染的元素。
<div id="app"> <child-component> <template scope="props"><!--props将数据传到插槽 临时变量--><!--通过临时变量props访问来自子组件插槽的数据msg--> <p>来自父组件的内容</p> <p>{{props.msg}}</p> </template> </child-component> </div> <script type="text/javascript"> Vue.component('child-component',{ props:{}, template:'<div class="container">\ <slot msg="来自子组件的内容"></slot>\ </div>' }) var app = new Vue({ el: '#app', data: { }, methods:{} }) </script>
最终渲染结果为
<div id="app"> <div class="container"> <p>来自父组件的内容</p> <p>来自子组件的内容</p> </div> </div>
作用域插槽更具代表性的是列表组件,允许组件自定义列表每一项如何渲染
<div id="app"> <my-list :books="books"> <template slot="book" scope="props"><!--作用域插槽也可以是具名slot--> <li>{{props.bookName}}</li> </template> </my-list> </div> <script type="text/javascript"> Vue.component('my-list', { props: { books:{ type:Array, default:function(){ return [] } } }, template: '<ul>\ <slot name="book"\ v-for="item in books"\ :book-name="item.name"\ ></slot>\ </ul' }) var app = new Vue({ el: '#app', data: { books:[ {name:'《我爸爸》'}, {name:'《我妈妈》'}, {name:'《我最爱我自己》'} ] }, methods: {} }) </script>
作用域插槽的使用场景就是既可以复用子组件的slot有可以使slot内容不一致。
访问slot
Vue2中提供了$slots来访问分发内容
<div id="app"> <child-component> <h2 slot="header">标题</h2> <p>正文内容</p> <p>更多正文内容</p> <div slot="footer">底部信息</div> </child-component> </div> <script type="text/javascript"> Vue.component('child-component',{ props:{}, 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(){//el挂载到实例上时调用,一般我们的第一个业务逻辑会写在这里 var header= this.$slots.header, main=this.$slots.default, footer=this.$slots.footer; console.log(header,main,footer) } }) var app = new Vue({ el: '#app', data: { }, methods:{} })
</script>
通过slots可以访问某个具名的slot,this.$slots.default包括来所有没有具名的slot