Vue 插槽
概述
插槽就是组件内的一个预留区域,它允许使用者向组件内的预留区域来添加自己想要的内容。
比如我们已经写好了一个组件,然后以后可能会在指定区域插入广告,这时就可以先用插槽进行占位。如果使用者向插槽中传递广告时,这时广告才会显示出来。
插槽大概分为三种:默认插槽、具名插槽、作用域插槽。
插槽通过 <slot></slot>
标签,在组件中占位。当标签内没有默认值时,如果使用者使用组件时,不插入自定义内容,那么插槽不会被渲染;如果使用者使用组件插入自定义内容时,插槽才进行渲染。如果插槽中有默认值时,如果插槽不被使用,则会输出默认值。
默认插槽
Skills.vue
<template>
<div id="skills">
<h2 id="title">skills</h2>
<hr />
<ul>
<li v-for="(skill, index) in skills" :key="index">{{ skill }}</li>
</ul>
<!-- 默认插槽 -->
<slot></slot>
</div>
</template>
<script>
export default {
name: "Skills",
props: ["skills"]
}
</script>
App.vue
<template>
<div id="app">
<div class="header">
<Skills :skills="skills">
// 组件标签内的所有内容将会被写到该组件中默认插槽的预留位置
<h2>默认插槽</h2>
</Skills>
</div>
</div>
</template>
<script>
import Skills from "./components/Skills.vue"
export default {
name: "App",
components: { Skills },
data() {
return {
skills: ["唱", "跳", "rap", "篮球"]
}
}
}
</script>
- 注意在书写样式时,结构在哪个文件,样式就书写到哪个文件中。
- 即使组件标签中的内容是要替换到组件插槽位置的,样式也要在组件标签所在的当前文件中书写。
- 因为组件标签中的内容是现在本文件渲染,然后才去替换组件插槽处的位置的。
具名插槽
当我们指定多个插槽时,就需要为插槽取名字了。因为默认插槽只能存在一个。
我们在使用插槽传入内容时,必须要使用 template 标签包裹内容,并指定要服务的具名插槽的名字。
Skills.vue
<template>
<div id="skills">
<h2 id="title">skills</h2>
<hr />
<ul>
<li v-for="(skill, index) in skills" :key="index">{{ skill }}</li>
</ul>
<!-- 默认插槽 -->
<slot></slot>
<!-- 具名插槽 -->
<slot name="slot01"></slot>
</div>
</template>
<script>
export default {
name: "Skills",
props: ["skills"]
}
</script>
App.vue
<template>
<div id="app">
<div class="header">
<!-- 默认插槽 -->
<Skills :skills="skills">
<h2>默认插槽</h2>
</Skills>
<!-- 具名插槽 -->
<Skills :skills="skills">
<template v-slot:slot01>
<div>
<h2>具名插槽</h2>
</div>
</template>
</Skills>
</div>
</div>
</template>
<script>
import Skills from "./components/Skills.vue"
export default {
name: "App",
components: { Skills },
data() {
return {
skills: ["唱", "跳", "rap", "篮球"]
}
}
}
</script>
- 具名插槽在插槽标签中使用 name 来给插槽起名字,以达到区分的作用。
- 具名插槽在组件标签使用时其中的结构必须使用
template
标签包裹,并且在该标签中使用v-slot:xxxx
指定所使用的具名插槽的名字。可以简写成#slot:xxx
。注意是冒号:
不是等号=
作用域插槽
作用域插槽并不是一种单独的插槽,而是实现插槽向使用者传递数据的一种插槽的称呼。
所以默认插槽可以是作用域插槽,具名插槽也可以是作用域插槽。
Skills.vue
<template>
<div id="skills">
<h2 id="title">skills</h2>
<hr />
<ul>
<li v-for="(skill, index) in skills" :key="index">{{ skill }}</li>
</ul>
<!-- 默认插槽的作用域插槽 -->
<slot :data="slotData"></slot>
<!-- 具名插槽的作用域插槽 -->
<slot name="slot01" :slotData="slotData"></slot>
</div>
</template>
<script>
export default {
name: "Skills",
props: ["skills"],
data() {
return {
slotData: {
content:"此数据由插槽传递给使用者"
}
}
},
}
</script>
App.vue
<template>
<div id="app">
<div class="header">
<!-- 默认插槽 -->
<Skills :skills="skills">
<h2>默认插槽</h2>
</Skills>
<!-- 具名插槽 -->
<Skills :skills="skills">
<template v-slot:slot01>
<div>
<h2>具名插槽</h2>
</div>
</template>
</Skills>
<!-- 具名插槽作用域插槽:接收插槽组件传给使用者的数据 -->
<Skills :skills="skills">
<template #slot01="scope">
<div>
<h2>作用域插槽</h2>
<p>{{ scope }}</p>
<p>{{ scope.slotData.content }}</p>
</div>
</template>
</Skills>
<!-- 默认插槽作用域插槽解构赋值 -->
<Skills :skills="skills">
<template scope="{data}">
<p>{{ data }}</p>
<p>{{ data.content }}</p>
</template>
</Skills>
</div>
</div>
</template>
<script>
import Skills from "./components/Skills.vue"
export default {
name: "App",
components: { Skills },
data() {
return {
skills: ["唱", "跳", "rap", "篮球"]
}
}
}
</script>
- 在插槽标签中,指定属性来向使用者传递值。
- 使用者可以在 template 标签中接收插槽传递的值。如果是具名插槽使用
#slot01="scope"
接收,scope 可自定义名字,为接收的数据对象。如果是默认插槽使用scope="scope"
接收。其中可以参照上面代码使用 es6 的解构赋值。