1.什么是插槽 ?
Vue
官方文档:
Vue
实现了一套内容分发的 API
,将 <slot>
元素作为承载分发内容的出口
个人理解:
子组件中的提供给父组件使用的一个占位符,使用 <slot>
表示,父组件可以在这个占位符中填充任何模板代码,填充的内容会替代子组件中 <slot>
标签,类似于种萝卜,一个萝卜一个坑,种不种萝卜由父组件决定,而萝卜在哪种由子组件决定
2.插槽的分类
根据插槽的使用场景,可以将插槽分为三种类型:
①.匿名插槽
②.具名插槽
③.作用域插槽
2.1.匿名插槽
匿名插槽,也称为单个插槽、默认插槽,就是没有 name
属性的插槽,可以放置在子组件的任意位置;但是一个组件只能由一个这样的插槽,作为备用插槽
实例:
父组件 parent.vue
:
<template>
<div class="parent-container">
<Child>
<test> 匿名插槽内容 </test>
</Child>
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
components: {
Child,
},
};
</script>
子组件 Child.vue
:
<template>
<div class="child-container">
<!-- 匿名插槽 -->
<slot>content</slot>
</div>
</template>
<script>
export default {
}
</script>
注意:当匿名插槽没有被使用时,显示匿名插槽中的默认内容
2.2.具名插槽
具名插槽,顾名思义,就是有名字的插槽,名字通过 name
属性来定义,一个组件中可以有很多的具名插槽,出现在组件的不同位置;我们可以在 template
标签上使用 v-slot
指令,并以v-slot
指令的参数绑定插槽的 name
名
案例:
父组件 Parent.vue
:
<template>
<div class="parent-container">
<Child>
<template v-slot:header>
<test>页头</test>
</template>
<test>主题内容</test>
<template v-slot:footer>
<test>页脚</test>
</template>
</Child>
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
components: {
Child,
},
};
</script>
子组件 Child.vue
:
<template>
<div class="child-container">
<div class="header">
<!-- 具名插槽 -->
<slot name="header"></slot>
</div>
<div class="main">
<!-- 匿名插槽 -->
<slot></slot>
</div>
<div class="footer">
<!-- 具名插槽 -->
<slot name="footer"></slot>
</div>
</div>
</template>
<script>
export default {
}
</script>
注意:1.任何不带有 v-slot
属性并未被 template
标签包裹的内容都会被当做匿名插槽内容
2.被 template
标签包裹不带 name
的插槽都会有一个默认名字 default
3.跟 v-on
和 v-bind
一样,v-slot
也有缩写,即把参数之前的所有内容 (v-slot:
) 替换为字符 #。例如 v-slot:header
可以被重写为 #header
:
<template>
<div class="parent-container">
<Child>
<template #header>
<test>页头</test>
</template>
<test>主题内容</test>
<template #footer>
<test>页脚</test>
</template>
</Child>
</div>
</template>
2.3.作用域插槽
插槽和模板其他地方一样都可以访问相同的实例属性(即相同作用域),而不能访问其它作用域,如果想访问其它作用域,那就需要把想访问的数据绑定到 <slot>
上,然后在父组件中用 v-slot
设置一个值来定义插槽的名字
案例:
父组件 Parent.vue
:
<template>
<div class="parent-container">
<Child :list="list">
<!-- 作用域插槽 -->
<template v-slot="prop">
<button class="edit" @click="edit(prop)">编辑</button>
<button class="delete" @click="del(prop)">删除</button>
</template>
</Child>
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
data() {
return {
list: [
{id: 3, name: "Tom"},
{id: 2, name: "Alice"},
{id: 1, name: "Jreey"}
]
}
},
components: {
Child,
},
methods: {
edit(prop) {
console.log(prop, "edit prop");
},
del(prop) {
console.log(prop, "del prop");
}
}
};
</script>
子组件 Child.vue
:
<template>
<div class="child-container">
<ul class="title">
<li>编号</li>
<li>姓名</li>
<li>操作</li>
</ul>
<ul v-for="item in list" :key="item.id">
<li>{{ item.id }}</li>
<li>{{ item.name }}</li>
<li class="oper">
<slot :row="item" :myId="item.id"></slot>
</li>
</ul>
</div>
</template>
<script>
export default {
props: ["list"]
}
</script>
注意:绑定在 <slot>
上的属性称为插槽 prop
,我们可以使用 v-slot
设置一个值定义我们提供的插槽 prop
的名字直接使用
2.3.1.解构插槽 Prop
作用域插槽的内部工作原理是将你的插槽内容包裹在一个拥有单个参数的函数里,这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式
3.动态插槽名
动态指令参数也可以用在 v-slot
上,来定义动态的插槽名:
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>