vue 插槽 slot
个人理解
- 个人感觉,为同一组件在不同的情况添加不同的内容,不需要专门修改组件,就像 java 的多态,来提高复用性。比如: 就像一块基础设施完备的土地,给你划分好区域,只要这个位置没有归属权(name),房子随便盖。
- 我们可以理解 slot 为占住当前的位置,方便我们插入内容。
-
Vue 的插槽分为匿名插槽(单个插槽/默认插槽)、具名插槽、作用域插槽(带数据的插槽)
-
vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot 指令)。它取代了 slot 和 slot-scope 这两个目前已被废弃但未被移除且仍有用的特性。但是将会在vue 3 中,被废弃的这两个,不会被支持即无效且不会出现在 Vue 3 中。
// 这是 home 组件模板 <template> <div class='home'> <p>我是home 组件</p> <slot> <h3>没传内容</h3> </slot> </div> </template> //home 组件的内部内容 <home>这是组件的内部内容</home>
-
slot 注意点
- vue 插槽的编译作用域的规则: 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。(个人理解: 各自管各自的,谁也别干预谁。也是用 props 和 $emit 传递数据的原因之一吧。)
-
组件模板中 没用 slot ,那组件内部 的内容 是不会被渲染的,直接抛弃。
<home> <span>{{msg}}</span> // 报错,Property or method "msg" is not defined on the instance but referenced during render // 组件内部的数据,不是组件的,是其 父元素节点的Property or method。父元素节点没有声明,肯定报错。 <p>是否能渲染</p> </home> // home 组件内部的内容全部会被抛弃,只渲染 home 的模板。等同于下面 <home></home>
-
插槽用
<slot>
标签来确定渲染的位置,只能用一个默认插槽。组件内部所有的HTML内容都会被渲染到 slot 的位置。除了 template 标签绑定了 v-slot 指令 的内容 。 - v-slot 指令, 它取代了 slot 和 slot-scope。
-
v-slot 简写把参数之前的所有内容
v-slot:
替换为字符#
。例如v-slot:header
可以被重写为#header
//具名 <template slot="header"> <template #header"> <!-- <template v-slot:header"> --> // 作用域 <template slot-scope="todo"> <template v-slot="todo"> // 具名-作用域 <template slot-scope="todo" slot='header'> <template #header="todo">
- v-slot属性只能在
<template>
上使用。
后备内容 和 匿名插槽(单个插槽/默认插槽)
后备内容
当组件内部没有内容时,组件模板中的slot标签的内容会被渲染。有则渲染组件内部的内容。
// home 组件模板
<template>
<div class='home'>
<p>我是home 组件</p>
<slot>
<h3>没传内容</h3>
</slot>
</div>
</template>
// 组件内部
<h2>组件内没有内容:</h2>
<home></home>
<h2>组件内有内容:</h2>
<home>
<h3>我有内容了</h3>
</home>
// 渲染结果
<h2>组件内没有内容:</h2>
<div class="home">
<p>我是home 组件</p>
<h3>没传内容</h3>
</div>
<h2>组件内有内容:</h2>
<div class="home">
<p>我是home 组件</p>
<h3>我有内容了</h3>
</div>
单个插槽( 匿名插槽/默认插槽)
- 单个插槽一般都是匿名的,无name属性。
注意: 组件模板中使用多个 slot 标签占位后,在组件内部的内容有多少个slot就会重复多少次。(多写几个默认插槽,怕是铁憨憨)
// home 组件模板
<template>
<div class='home'>
<p>我是home 组件</p>
<slot>
<h3>没传内容</h3>
</slot>
<slot></slot>
<slot></slot>
</div>
</template>
//组件内部
<home>
<p>铁憨憨</p>
</home>
//渲染结果
<div class="home">
<p>我是home 组件</p>
<p>铁憨憨</p>
<p>铁憨憨</p>
<p>铁憨憨</p>
</div>
-
单个插槽当然也可以给他命名,默认未命名情况下,Vue2.6+版本默认为
v-slot:default或简写#default
。也可以省略default直接写v-slot
。如果写写上#default或者 v-slot
,单个插槽变成了具名插槽。// home 组件模板 <template> <div class='home'> <p>我是home 组件</p> <slot> <!-- slot的name=default 写不写都一样 --> <h3>没传内容</h3> </slot> </div> </template> // <home > <p>我是 slot </p> <template v-slot> <p>我变成具名插槽了</p> </template> </home>
// 渲染结果
<div class="home">
<p>我是home 组件</p>
<p>我变成具名插槽了</p>
</div>
```
具名插槽
- 匿名插槽没有name属性,所以是匿名插槽,那么,插槽加了name属性,就变成了具名插槽。具名插槽可以有N个。但是 name 和 v-slot:'插槽名' 是一一对应的。
- 具名的作用,也就是指向到那个位置展示。也和在组件内部的书写顺序无关。
- 在向具名插槽提供内容的时候,我们要在一个
<template>
标签上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称。
//home组件
<div class='home'>
<p>我是home 组件</p>
<slot name=header></slot>
<slot name='bar'></slot>
</div>
//内部
<homse >
<p>我是 default </p>
<template v-slot:header>
<p>v-slot:header 我变成具名插槽了</p>
</template>
<template #bar>
<p>#header 我变成具名插槽了</p>
</template>
</homes>
//渲染结果
<div class="home">
<p>我是home 组件</p>
<p>v-slot:header 我变成具名插槽了</p>
<p>#bar 我变成具名插槽了</p>
</div>
作用域插槽(带数据的插槽)
- 其实就是获取父组件的内部数据。不用像父子组件通信一样的麻烦。
-
绑定在 <slot> 元素上的 属性 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字(注意: v-slot 定义的名字 可以和 prop 的名字不同,但是结构的时候需要重命名 prop) 。并且 slot 标签上返回的属性值,是以一个对象的形式保存起来。
<template v-slot='res'> <h2>在 slot 上面绑定属性,得到父组件的数据,通过v-slot获取</h2> <h4>{{res}}</h4> </template> // <p>我是home 组件</p> <h2>在 slot 上面绑定属性,得到父组件的数据,通过v-slot获取</h2> <h4> { "res": { "name": "作用域插槽", "type": "Object" } } </h4>
- 默认插槽 携带数据,会被当作具名插槽使用,slot 的 name 默认为 default。只会渲染 最后一个
<template #default='res'>
标签。 -
具名插槽带数据,
v-slot:bar='res'
简写为#bar='res'
。<template > <h2>得到数据</h2> <h4>{{res}}</h4> </template> <template #bar='res'> <h2>具名插槽得到数据</h2> <h4>{{res}}</h4> </template> // <h2>具名插槽得到数据</h2> <h4> { "res": { "name": "作用域插槽", "type": "Object" } } </h4>
-
解构Prop,由于返回的是一个对象,那就可以解构。可以使接受的数据变得更简洁。
<template #prop='{res}'> <h2>解构插槽 Prop</h2> <h4>{{res}}</h4> </template> // <h2>解构插槽 Prop</h2> <h4> { "name": "作用域插槽", "type": "Object" } </h4>
-
尤其是在该插槽提供了多个 prop 的时候。它同样开启了 prop 重命名等其它可能,例如将 user 重命名为 person:
v-slot={"user": person}
。其实就是解构Prop。<template #other='{"res": other}'> <h2>prop 重命名 </h2> <h4>{{other}}</h4> </template> // <h2>prop 重命名 </h2> <h4> { "name": "作用域插槽", "type": "Object" } </h4>
-
你甚至可以定义后备内容,用于插槽 prop 是 undefined 的情形。
<template #uf='{uf = {arr:[1]}}'> <h2>用于插槽 prop 是 undefined 的情形:</h2> <h4>{{uf}}</h4> </template> // <h2>prop 重命名1 </h2> <h4> { "arr": [ 1 ] } </h4>
-
当被提供的内容只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。这样我们就可以把 v-slot 直接用在组件上。
<home v-slot='{res}'> {{res.name}} </home>
- 代码
<tempalte>
<div class='home'>
<p>我是home 组件</p>
<slot :res=res ></slot>
<slot :res=res name=bar></slot>
<slot :res=res name=prop></slot>
<slot :res=res name=other></slot>
<slot :uf=uf name=uf></slot>
</div>
</tempalte>
export default {
name:"home",
data() {
return {
"res":{
"name": 作用域插槽,
"type": "Object",
},
"uf": undefined,
}
},
}
转载及引用
官方插槽文档[[Vue] slot详解,slot、slot-scope和v-slot](https://juejin.im/post/5cb056...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。