您好,我是bp技术知识库,欢迎关注。
插槽在Vue中是一个十分常见以及经常会使用到的功能,它的存在大大提高了组件的复用性,很多时候我们都需要使用插槽来将组件进行复用。
在平时的插槽使用中,我们大部分时间都仅仅使用了插槽的一些简单功能,但其实插槽还有更多高级的功能,比如说能将子组件中的数据传递到父组件中,父组件中能够访问到该传递的数据。
因为一些原因,官方已经废弃了之前插槽的用法,相信只要使用Vue框架的人肯定都用过Element UI,但其实Element UI的表格插槽使用方式其实现在已经过时了,就如下面代码。
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
<el-button type="text" size="small">编辑</el-button>
</template>
官方声明在Vue3.x版本时,已经不再对这种插槽使用方式进行支持。
1. 写法
插槽的使用是非常简单的,这里要分两种情况:
- 默认插槽:即
<slot />
这种不带name属性的为默认插槽,但是在某些情况下,我们需要在不同的地方插入不同的值,所以就需要使用到具名插槽。 - 具名插槽:即
<slot name="header" />
这种带有name
属性的插槽。
其实<slot />
这种默认插槽是附带了name
属性的,只是它的name
属性为default
,在一般情况下我们会将它进行省略。
下面我们分别来看一下默认插槽和具名插槽。
<template>
<div>
<header>
<!-- 这里是具名插槽 -->
<slot name="header" />
</header>
<!-- 这是默认插槽 -->
<!-- 下面这两种插槽本质都是默认插槽 -->
<slot />
<slot name="default" />
</div>
</template>
<script>
export default {
name: "SlotTest"
};
</script>
<style>
header {
font-size: 30px;
font-weight: bold;
}
</style>
上面这段代码分别声明了默认插槽和具名插槽,其中同名的插槽是可以多次声明的,并不是只能声明一次。
当声明多次的时候,插入的内容也会变成两份。例如我们使用以下默认插槽:
<slot-test>
Hello default slot!
</slot-test>
这个时候运行项目,会发现在浏览器中会出现两个Hello default slot!
。
那么大概知道了这些内容后,我们就来看一下具名插槽和默认插槽分别是怎么用的。
推荐写法
官方在2.6.0
版本中,修改了插槽的用法,现在推荐使用<template v-slot:header>
这种写法来调用具名插槽。
<slot-test>
<!-- 具名插槽的用法 -->
<template v-slot:header>
Hello header slot!
</template>
<!-- 这是一种默认插槽的用法 -->
<template v-slot:default>
Hello header slot!
</template>
<!-- 这是另一种默认插槽的用法 -->
Hello header slot!
</slot-test>
需要注意的是,v-slot
属性只有当标签为<template />
才会生效,如果是其它标签是无法调用插槽的,例如:
<div v-slot:header>
Hello header slot!
</div>
不仅不能调用,甚至还会报错。
值得注意的是,v-slot
跟v-on
和v-bind
一样,也有缩写,那就是#
,所以上面的代码也可以写成下面这样:
<slot-test>
<!-- 具名插槽的用法 -->
<template #header>
Hello header slot!
</template>
<!-- 这是一种默认插槽的用法 -->
<template #default>
Hello header slot!
</template>
<!-- 这是另一种默认插槽的用法 -->
Hello header slot!
</slot-test>
过时写法
由于官方文档的排版问题,我在最开始读文档的时候搞不清哪个是过时用法,反复读了几遍后,终于发现<div slot="header"></div>
这种语法使用插槽就为过时语法,官方在文档说在Vue3
中不会再兼容这种写法:
<slot-test>
<div slot="header">
Hello header slot!
</div>
</slot-test>
与上面的推荐写法不同,slot
不仅仅可以声明在<template />
标签上,还可以声明在其它的HTML标签上面,比如上面的div
标签。
2. 向父组件传值
有时候我们需要将子组件中的属性值传递到父组件,让父组件在使用插槽的时候能够取得这些值,例如下面的代码:
<template>
<div>
<header>
<!-- 这里是具名插槽 -->
<slot name="header" />
</header>
<!-- 这是默认插槽 -->
<!-- 下面这两个插槽本质是同一个 -->
<slot />
<slot name="default" />
</div>
</template>
<script>
export default {
name: "SlotTest",
data() {
return {
// 该值希望在父组件中可以获取并且调用
describe: "插槽的使用"
};
}
};
</script>
<style>
header {
font-size: 30px;
font-weight: bold;
}
</style>
可以看到,我们希望在父组件中获取到子组件的describe
值,那么这种情况怎么进行处理呢?
<slot-test>
{{ describe }}
Hello header slot!
</slot-test>
像上面这种方式直接尝试调用describe
属性显然是不现实的,会直接进行报错,那么我们就来看一下究竟如何在父组件中获得describe
属性值吧。
2.1 推荐写法
官方在2.6.0
版本中同样修改了这一部分的写法。
首先我们要想在父组件中获得该属性,就必须在插槽上面进行传递:
<div>
<header>
<slot name="header" :describe="describe" />
</header>
<slot :describe="describe" />
</div>
这个时候在父组件中就可以获取到传递出来的describe
值:
<slot-test v-slot="slotProps">
{{ slotProps.describe }}
</slot-test>
注意:子组件中传出来的是一个对象,即:{ "describe": "插槽的使用" }
。并不是describe
的值,所以slotProps
这个变量其实取什么名字都是可以的。
具名插槽也是同样:
<slot-test>
<template #header="slotProps">
{{ slotProps.describe }}
</template>
<!-- 一旦有具名插槽,默认插槽就必须这样写 -->
<template v-slot:default="slotProps">
{{ slotProps.describe }}
</template>
</slot-test>
需要值得注意的是,一旦有了具名插槽,默认插槽就不能再像上面一样,直接声明到slot-test
上,这会导致作用域不明确而报错。
2.1.1 解构插槽Prop
插槽Prop是可以直接通过ES6语法来解构的:
<slot-test>
<template #header="{ describe }">
{{ describe }}
</template>
<!-- 一旦有具名插槽,默认插槽就必须这样写 -->
<template v-slot:default="{ describe }">
{{ describe }}
</template>
</slot-test>
2.2 过时写法
过时写法看一下就好了,虽然Element UI的表格那块插槽示例依然还是这种写法,但是Vue官方已经不推荐了。
<slot-test>
<template slot="header" slot-scope="slotProps">
{{ slotProps.describe }}
</template>
<!-- 这是过时写法 -->
<template slot-scope="slotProps">
{{ slotProps.describe }}
</template>
</slot-test>
3. 最后
插槽的用法是非常灵活的,知道了上面的那些基础知识后,你也可以制作出一些十分方便的组件。
同时非常推荐去读一下官方文档中的插槽介绍,你可能会发现一些新大陆。