Vue slot插槽
我们对于slot这个概念或许不是很清楚,但是我们在实际的使用中可能已经遇到很多次了。比如我们在使用ivew组件库的时候,就会经常遇到slot这个单词。而实际上,slot的使用更多的是用于独立组件的开发,在加上前面我们了解过的props和events事件,这3个东西可以完成vue中各种复杂的组件。slot我们中文的翻译是插槽,举个例子,我们中秋节都会吃月饼吧,可是月饼的样子也可能是千奇百怪的,所用.
我们对于slot这个概念或许不是很清楚,但是我们在实际的使用中可能已经遇到很多次了。比如我们在使用ivew组件库的时候,就会经常遇到slot这个单词。而实际上,slot的使用更多的是用于独立组件的开发,在加上前面我们了解过的props和events事件,这3个东西可以完成vue中各种复杂的组件。
slot我们中文的翻译是插槽,举个例子,我们中秋节都会吃月饼吧,可是月饼的样子也可能是千奇百怪的,所用到的模具也是各不相同。假如有一个厂家接了一个单子,如果客户没有特别的需求,那么他们就会使用自己的模具制作中规中矩的月饼,但是,有一个客户给了厂家一个特别的模具,那么这个月饼的样子就改变了。
所以slot就相当于一个占位的东西,如果你没有给我提供具体的内容,那么我就是用默认的内容来显示。如果,你自己写了该内容,那么默认的内容就没有效果了,显示的自然是你的东西。同时,这里我们顺带提一下关于slot的作用域的问题,前面那么例子,不管模具怎么变,但是制作月饼的厂商并没有改变,也就是说slot内容的作用域其实还是在父组件中的。在编译过程中,父组件的内容在父组件的作用域内编译,子组件的内容在子组件中编译。比如:
<child-componet v-show="visible"></child-componet>
....
data(){
return{
visible:true
}
}
上面是一个简单到示例,child-component是我们定义的一个组件,在我们的父组件中使用,其中它的显示和隐藏依赖于父组件的visible变量,在这里,child-component使用了父组件的数据,所以slot分发的内容其实作用域是在父组件上。
slot最简单的使用方式就是在我们的子组件内使用特殊的slot元素为这个子组件开启一个slot,在父组件的模板中,插入这个子组件标签内的所有内容都将代替子组件的slot标签以及它的内容。
<template>
<div>
<child-component></child-component>
<child-component>
<p>父组件给你写点东西吧。</p>
</child-component>
</div>
</template>
<script>
export default {
name: "VSlot",
components: {
'child-component': {
template: '\
<div >\
<slot >\
<p style="border: 1px solid saddlebrown; margin-bottom: 20px;width: fit-content;">父组件没有给我内容,那我就出来了!</p>\
</slot>\
</div>'
},
}
}
</script>
<style scoped>
</style>
运行效果:
在很多的场景下,我们可能仅仅希望替换指定区域的内容,此时,上面单一的slot就无法满足我们的要求了。我们想一下,假使我们有多个内容区域,都是用slot的话,如果没有一个标志能够区分这些slot,那么对于我们来说就没有办法实现我们的要求了,谁知道到时候修改的是哪一个,也许是第一个吧?实际结果呢,它会把所有的slot都进行替换的。
就像下面的示例一样,我们不过是又加了一个slot而已。
此时,大家也看很容易想到vue会采用什么样的解决方法,很简单,那就是给我们的slot加一个name属性用来区分不同的slot,这也就是具名slot的概念。
<template>
<div>
<child-component></child-component>
<child-component>
<p>父组件给你写点东西吧。</p>
</child-component>
</div>
</template>
<script>
export default {
name: "VSlot",
components: {
'child-component': {
template: '\
<div style="margin-bottom: 20px;">\
<slot name="header">\
<p>header区域</p>\
</slot>\
<slot>\
<p>内容区域</p>\
</slot>\
<slot name="footer">\
<p>footer区域</p>\
</slot>\
</div>'
},
}
}
</script>
<style scoped>
</style>
运行效果:
接下来我们试着修改header区域的内容:
<p slot="header">父组件给你写点东西吧。</p>
运行效果:
这里我们总结一下相关的语法,在子组件内给slot使用name属性,记得是在slot标签内使用name。
在父组件中,如果我们要自定义某一个slot的内容那么我们需要使用slot=“***”的方式来指定slot,其中slot的值必须和我们在子组件中定义的name是一样的,不然找不到自然不会有效果的。
最后我们说一下作用域slot,它是一种特殊的slot,使用一个可以复用的模板替换已经渲染的元素。让我们一起看个例子:
<template>
<div>
<child-component></child-component>
<child-component :contents="chineseBooks">
<template slot="contents" scope="props">
<li>{{props.bookName}}</li>
</template>
</child-component>
</div>
</template>
<script>
export default {
name: "VSlot",
data() {
return {
chineseBooks: [{name: '三国演义'}, {name: '水浒传'}]
}
},
components: {
'child-component': {
props: {
contents: {
type: Array,
default() {
return [{name:'西游记'},{name:'红楼梦'}]
}
}
},
template: '\
<ul>\
<slot name="contents" v-for="item in contents" :book-name="item.name">\
{{item.name}}\
</slot>\
</ul>'
},
}
}
</script>
<style scoped>
</style>
运行效果:
在上面的例子中,和前面的比较,我们在这里使用了template模板,在这个模版上面,我们可以绑定我们自己的数据给子组件,同时我们可以使用scope这个属性来声明一个临时变量,而这个变量则可以访问子组件中的数据。
大家可以看到效果,如果我们没有使用作用域slot,那么给我们渲染出来的就会是一个ul无序列表,使用作用域slot后,我们得到的则是一个li有序列表。
这里大家可以看到,其实使用作用域slot最大的特点是,我们可以使用子组件的元素来重新渲染内容。
这一点其实是十分有用的,一般情况下,我们在父组件中完成给子组件的数据传递,然后子组件进行渲染。向上边的例子,如果我们没有办法获取到父组件中的变量,那么即使我们重写了这个slot,那么我们最后会纠结在我们怎么访问子组件的数据来完成我们自定义的渲染。比如,我们使用同一个组件,有时候需要使用name属性,有时候有需要显示publisher属性,我们不可能一直重复去写这个组件,若数量少还好,如果多的话岂不是十分麻烦?
归根结底一句话,如果我们希望在父组件中能够使用子组件的数据来完成自定义的渲染效果,那么请使用作用域slot。
关于这个概念,我说的不是很明白,推荐大家去看看官方文档。
更多推荐
所有评论(0)