你使用的Vue插槽(slot)语法可能已经过时了
您好,我是沧沧凉凉,是一名前端开发者,目前在掘金、知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。
插槽在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. 最后
插槽的用法是非常灵活的,知道了上面的那些基础知识后,你也可以制作出一些十分方便的组件。
同时非常推荐去读一下官方文档中的插槽介绍,你可能会发现一些新大陆。