简述
vue提供的插槽功能,实现了在 使用子组件时,为子组件提供结构 的功能。
比如,封装对话框组件的时候,对话框内容是什么?标题又是什么?
这些不确定的内容应该由使用者(父组件)提供才对。这时,就需要用插槽功能
插件的基本语法
- (子组件全局注册过)
上述,定义子组件(对话框组件)的时候,我们希望使用者(父组件)在使用按钮组件的时候,为其提供结构,所以
- 子组件:在
<div class="dialog"></div>
内使用一对<slot>
标签占位。表示这里要放一些内容,相当于在这里挖了一个坑位,准备存储内容; - 父组件:使用子组件的时候,在标签中间,为插槽(前面的坑位),传递内容
具名插槽
槽还有另外两种情况,分别是
- 具名插槽(具有名字的插槽)
- 作用域插槽(插槽可以为父组件提供数据)
下面先看具名插槽:
作用域插槽
有些时候,子组件在定义插槽的时候,需要向使用者(父组件)传递一些数据,这样的插槽叫做作用域插槽。
<template>
<div>
<h2>App组件</h2>
<MyDialog>
<!-- 标签内的所有代码,都是给插槽传递的结构 -->
<!-- <template v-slot:title="obj"> -->
<template v-slot:title="{ uname, age }">
<!-- 接收到的值,只能在当前的template里面用,所以这类插槽叫做 作用域插槽 -->
添加学员 {{ uname }} {{ age }}
</template>
</MyDialog>
</div>
</template>
<script>
import MyDialog from './components/MyDialog.vue'
export default {
components: { MyDialog },
}
</script>
子代码组件
<template>
<div class="dialog">
<!-- 使用 slot 标签,站位,表示这里要放页面结构 -->
<h3>
<!-- 只要包含有除name以外的其他属性的插槽,叫做作用域插槽 -->
<slot name="title" uname="zs" age="20">标题</slot>
</h3>
</div>
</template>
<style>
.dialog {
padding: 5px;
margin: 10px;
border: solid 2px black;
border-radius: 5px;
box-shadow: 5px 5px 2px 2px;
}
</style>
案例(补充说明)
父组件有一些数据,需要传给子组件,然后遍历展示,并且做删除效果。
父组件代码:
<template>
<div>
<h2>列表数据</h2>
<my-list :list="list">
<template #default="{ id }">
<button @click="del(id)">删除</button>
</template>
</my-list>
<my-list :list="goods">
<template #default="{ id }">
<button>编辑</button>
<button>查看详情</button>
<button @click="delGoods(id)">删除</button>
</template>
</my-list>
</div>
</template>
<script>
import MyList from './components/MyList.vue'
export default {
components: { MyList },
data () {
return {
list: [
{ id: 2, name: "关羽" },
{ id: 4, name: "张飞" },
{ id: 5, name: "赵云" },
{ id: 7, name: "黄忠" },
{ id: 8, name: "马超" },
],
goods: [
{ id: 2, name: "方便面" },
{ id: 4, name: "鸡爪子" },
{ id: 5, name: "火腿肠" },
{ id: 7, name: "大辣条" },
{ id: 8, name: "卤鸡蛋" },
]
}
},
methods: {
del (id) {
// console.log('做删除', id)
this.list = this.list.filter(item => item.id != id)
},
delGoods (id) {
this.goods = this.goods.filter(item => item.id != id)
}
}
}
</script>
子组件 MyList.vue (注意:动态传的数据名称保持一致)
<template>
<div>
<h2>列表数据</h2>
<my-list :list="list">
<template #default="{ id }">
<button @click="del(id)">删除</button>
</template>
</my-list>
<my-list :list="goods">
<template #default="{ id }">
<button>编辑</button>
<button>查看详情</button>
<button @click="delGoods(id)">删除</button>
</template>
</my-list>
</div>
</template>
<script>
import MyList from './components/MyList.vue'
export default {
components: { MyList },
data () {
return {
list: [
{ id: 2, name: "关羽" },
{ id: 4, name: "张飞" },
{ id: 5, name: "赵云" },
{ id: 7, name: "黄忠" },
{ id: 8, name: "诸葛卧龙" },
],
goods: [
{ id: 2, name: "方便面" },
{ id: 4, name: "肉蛋葱鸡" },
{ id: 5, name: "火腿肠" },
{ id: 7, name: "大辣条" },
{ id: 8, name: "土豆片" },
]
}
},
methods: {
del (id) {
// console.log('做删除', id)
this.list = this.list.filter(item => item.id != id)
},
delGoods (id) {
this.goods = this.goods.filter(item => item.id != id)
}
}
}
</script>
其他补充
子组件,定义默认插槽(<slot>
)时
- 默认插槽
<slot></slot>
插槽其实也有名字,名字是default
<slot>
可以省略掉name="default"
- 可以在
<slot>......</slot>
点点点的位置,设置插槽的默认值
父组件,使用插槽时
- 使用插槽时,没有被包裹在
<template v-slot:xxx>
中的内容都会被视为默认插槽的内容 - 使用插槽时,
v-slot:abc
可以简写为#abc
- 给插槽传递内容的时候,可以将其他组件传进去。
<MyDialog>
<MyTest></MyTest>
</MyDialog>
- 我们学的是新版的插槽(适用于vue2和vue3)。老版本的插槽参见这里。
- 老版本的
slot
相当于 新版的v-slot
老版本的slot-scope="obj"
相当于 新版的v-slot:default="obj"
(作用域插槽)