深入浅出 Vue 中的插槽 slot
start
- 最近被问到好几次 Vue 中的插槽相关知识,掌握的还是有些不全面。
- 抱着重新学习的心态,写这篇博客。首先对基础知识做一个回顾,然后再对源码实现做一个学习。
- 作者:番茄
- 编写时间:2023/11/27
1.什么是插槽?
在日常代码编写的过程中,针对高频出现的业务场景,我会它把封装一个组件,然后多个地方去使用。
但是在某些情况下,一个组件并不能兼容所有的场景。
就比如对话框组件,可能每个人都会用到对话框,但是对话框中的内容会根据需求千变万化。这个时候就要考虑有没有什么方法,可以让我们对话框中的内容变成动态的呢?
答案:有,使用插槽就可以满足我们的需求。
插槽的概念有点类似 JavaScript 中的插值表达式,在代码在保留一个占位符,然后动态的向占位符中传入内容。
// 插值表达式
var name = '番茄'
var str = `<div>
我是 ${name}
</div>`
2. 插槽的使用
上面提到了插槽,现在我们结合示例,一步一步学习插槽的用法
1. 父组件引入子组件的基本用法
父组件 app.vue
<template>
<div id="app">
<Son></Son>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
};
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件 son</h1>
</div>
</template>
运行效果
总结
上面的示例展示了一个基本的父组件使用子组件的用法。
2. 父组件在子组件中传入文本
父组件 app.vue
<template>
<div id="app">
<Son>
向子组件中传入文本
</Son>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
};
</script>
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件 son</h1>
</div>
</template>
运行效果
总结
在父组件中使用子组件,当子组件中没有插槽没有 <slot></slot>
的时候,在父组件中向子组件中传递内容,这些内容并不会展示。
3.基础插槽的使用(不传入内容)
父组件 app.vue
<template>
<div id="app">
<Son> </Son>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
};
</script>
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件 son</h1>
<slot>
我是插槽的默认内容
</slot>
</div>
</template>
运行效果
总结
上面的示例是一个基础的插槽使用演示。父组件使用子组件,但是不向子组件传入内容,此时,展示的内容是 <slot>默认内容</slot>
中默认的内容。
4. 基础插槽的使用(传入内容)
父组件 app.vue
<template>
<div id="app">
<Son>
这是我自己DIY的内容
</Son>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
};
</script>
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件 son</h1>
<slot>
我是插槽的默认内容
</slot>
</div>
</template>
运行效果
总结:
上面的示例是一个基础的插槽使用演示。父组件使用子组件,且向子组件传入内容。
此时,展示的内容是我们在父组件中传入的内容。此时就可以满足我们定制化的需要了。
这就是最基础的组件使用方法了
5. 同一个子组件,需要多个插槽如何处理?
掌握了插槽的基础使用方法后,会有一个衍生的问题。
如果同一个组件中需要多个插槽,如何处理?
答: 可以使用
具名插槽
,顾名思义,就是可以给插槽取名字,然后根据名称去匹配插槽。
父组件 app.vue
<template>
<div id="app">
<Son>
这是我自己DIY的内容
<template v-slot:lazy>
LAZY
</template>
<template v-slot:tomato>
TOMATO
</template>
</Son>
</div>
</template>
<script>
import Son from "./son.vue";
export default {
components: {
Son,
},
};
</script>
<style>
#app {
width: 400px;
height: 400px;
background: pink;
}
</style>
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件 son</h1>
<br />
<slot> 我是什么都不写的插槽 </slot>
<br />
<slot name="lazy"> 我是lazy </slot>
<br />
<slot name="tomato"> 我是tomato </slot>
<br />
<slot> 我是什么都不写222 </slot>
<br />
<slot name="lazy"> 我是lazy </slot>
</div>
</template>
<style>
.son {
background: yellow;
}
</style>
运行效果
总结
由上面的运行效果,我们知道:
-
针对一个组件中有多个插槽的情况,我们可以使用
name
对插槽进行命名。然后在父组件中使用插槽的时候,使用<template>
标签,加上v-solt:对应插槽名称
的形式匹配到对应的插槽; -
在子组件组件中,没有写
name
属性的插槽,会默认的使用default
名称,然后匹配没有被template
标签包裹的内容; -
子组件中相同
name
的插槽可以有多个;既然同一个组件中,可以存在多个相同
name
的插槽,是不是可以利用这个特性,实现重复内容的复制? -
在使用
v-solt
的时候,注意使用的是:
冒号连接,而且子组件绑定名称的时候,name=
的后面不需要添加引号。我在编写示例的时候,将
v-slot:lazy
误写成v-slot=lazy
的形式了,发现代码并不生效。所以请注意使用的是冒号v-slot:
类似v-on: v-bind:
都是指令,所以这个地方不要弄混淆了。 -
v-slot:
也和v-on: v-bind:
类似,有语法糖#
代替即可。 -
v-slot:
单词不要打错了!!正确写法:**slot**
6. 作用域插槽
除了具名插槽,还有一种插槽:作用域插槽。
绝大多数情况,上面介绍的两种方式已经满足我们的业务需求了。
- 插槽默认值;
- 父组件定义插槽内容;
这两种方式,展示的数据和形式,由父组件控制。
但是还有一种情况,就是希望可以拿到子组件的数据,然后父组件控制如何展示。
这个时候就需要使用作用域插槽了。
子组件可以设置插槽的数据,然后数据如何展示,由外部的组件决定。
首先在子组件中绑定一个数据
:sonList="list" :向外暴露的变量名="子组件内部的变量名"
>子组件
子组件 son.vue
<template>
<div class="son">
<h1>我是子组件</h1>
<br />
<slot name="lazy" :sonList="list"> </slot>
</div>
</template>
<script>
export default {
data() {
return {
list: [
{
index: 1,
name: '张三',
},
{
index: 2,
name: '李四',
},
{
index: 3,
name: '王五',
},
{
index: 4,
name: '赵六',
},
],
}
},
}
</script>
然后就是在父组件区使用我们的子组件,然后定义子组件插槽渲染的内容
v-slot:lazy="data"
,首先使用v-slot:lazy
绑定我们的数据。然后在后面接等于号,用data
去接收,然后再用data.子组件暴露的变量名使用
父组件 app.vue
<template>
<div id="app">
<Son>
<template v-slot:lazy="data">
LAZY
{{ data.sonList }}
</template>
</Son>
</div>
</template>
<script>
import Son from './son.vue'
export default {
components: {
Son,
},
}
</script>
总结
-
作用域插槽的使用方式:
v-slot:插槽名="接收的变量名":<template v-slot:插槽名="接收的变量名">
-
其实本质上就是子组件向外暴露数据,父组件控制子组件具体展示。
小结
本文主要对 Vue 中的插槽的使用做了一个基础说明。
按照插槽的类型区分,可以分为三类:
- 默认插槽;
- 具名插槽;
- 作用域插槽;
- 默认插槽就是绑定默认的内容;
- 具名插槽就是给插槽定义名称,用以区分组件;
- 作用域插槽就是子组件向外暴露数据,由父组件完全控制插槽内容的展示。
end
插槽的使用,整体难度不大。注意一下使用的语法即可。