<dialog-panel> <template slot="header"> <div> <h3>带名字的插槽</h3> <button>x</button> </div> </template> <template slot="content"> <div>这是一个标准的 dialog 对话框</div> </template> <template slot="footer"> <div> <el-button type="primary" plain>取消</el-button> <el-button type="primary">确定</el-button> </div> </template> </dialog-panel>
可以看到,我们在外部可以控制组件的全部内容只要我们需要,这给我们的组件带来了很高的灵活性。除了灵活性,Vue 中还给我提供了一种叫 作用域插槽 的用法,它让我们的组件更加的复用性。
具名插槽不仅仅只能用在 <template> 元素上,它也可以直接用在一个普通的元素上
<div slot="header"> <h3>带名字的插槽</h3> <button>x</button> </div>
作用域插槽
作用域插槽在 Vue 中是一个非常重要的一个功能,它让组件更加的可复用性,但是官方文档上对作用域插槽的解释很令人蛋疼,反正我是看了几遍不是太理解,最后通过自己写了几个案例才明白原来可以这么厉害,如果你也和我一样一开始不太理解,不妨跟着我看看下面的案例或许对你的帮助很大。
首先我们实现一个星级评价组件
<template> <div> <span v-for="(star, index) in stars" :key="index" @click="clickStart(index)" > <i v-bind:class="[star ? off : on]"></i> </span> </div> <template> <script> export default { name: "RateList", data() { return { off: "el-icon-star-off", on: "el-icon-star-on", rating: 2 }; }, methods: { clickStart(index) { this.rating = index + 1; } }, computed: { stars() { return [1, 2, 3, 4, 5].map(value => this.rating < value); } } }; </script>
这是我们写死的一个星级评价组件,一直都用着还不错,可是突然有一天呢,产品说这个小星星用腻歪了能不能换个别的图标?我最近爱上了 :heart: 形
所以用这个表示吧。到这里,你可能也想到了我们把这个图标给抽离出来,放在外部,所以我们结合上面刚刚学到的 <slot> 元素去修改组件。
<div> <slot></slot> </div>
在父组件中使用:
<rate-list> <span v-for="(star, index) in stars" :key="index" @click="clickStart(index)" > <i v-bind:class="[star ? off : on]"></i> </span> </rate-list>
完成之后呢,我们再也不怕以后更换内容的情况了,不管以后怎么换,我都可以在使用的时候直接在外部添加内容即可,但是似乎有一些问题,因为我们的代码看起来不是很优雅,而且我们把操作逻辑都放在的父组件中,这显然不太友好,最好的方式肯定是我们只需要在父组件中直接调用即可,所以作用域插槽这里就起到很大的作用了,我们来看看如果使用作用域插槽是如何保持优雅的。
<div> <span v-for="(star, index) in stars" :key="index" @click="clickStart(index)" > <slot :star="star"></slot> </span> </div>
在父组件中使用:
<div> <span v-for="(star, index) in stars" :key="index" @click="clickStart(index)" > <slot :star="star"></slot> </span> </div>
可以看到我们把操作逻辑全部都放在了组件内部,在外部我们只需要添加需要的元素即可,简单优雅高复用性。
在 Vue2.5.0+,slot-scope 不再限制在 <template> 元素上使用,而可以用在插槽内的任何元素或组件上
有些同学看到这里可能还没有很好的理解 作用域插槽 ,那好吧我就送佛送到西,咱继续看一个例子,我们创建一个列表面板组件。
<template> <div> <h1>{{title}}</h1> <ul> <li v-for="(item, index) in list" :key="index"> <slot :item="item"></slot> </li> </ul> </div> </template> <script> export default { name: "List", props: { title: String, list: Array } }; </script>
在父组件中使用: