Vue学习之插槽slot
1. 插槽是什么
-
插槽就是子组件中的提供给父组件使用的一个占位符,用
<slot></slot>
表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的标签。 -
插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。
-
简单理解就是子组件中留下个“坑”,父组件可以使用指定内容来补“坑”。
-
让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件向子组件传值。
2. 插槽分类
- 匿名插槽
- 具名插槽
- 作用域插槽
3. 插槽的基本使用
3.1 匿名插槽
匿名:即是 name 默认为 default 的情况
3.1.1 基本使用(及作用)
父组件:
<template>
<div>
<p>我是A父组件</p>
</div>
</template>
<script>
export default {
name:'A',
data(){
return {
}
}
}
</script>
子组件:
<template>
<div>
<p>我是B子组件</p>
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
}
}
}
</script>
子组件不使用slot占位,在父组件中使用子组件后在组件内传入dom无效
如果我们想要直接在子组件标签中写内容,是不生效的,如:123,指定内容123会被丢弃。
<template>
<div>
<p>我是A组件</p>
<B>123<B/>
</div>
</template>
<script>
import B from './B.vue' //引入B组件
export default {
name:'A',
components:{ //注册B组件
B
},
data(){
return {
}
}
}
</script>
应该在子组件中使用插槽slot:
<template>
<div>
<p>我是B组件</p>
<!-- 插槽占位 -->
<slot></slot>
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
}
}
}
</script>
此时,再在子组件标签中写内容,生效:
<template>
<div>
<p>我是A组件</p>
<!-- 用B组件标签包裹内容,验证slot -->
<B>123</B>
</div>
</template>
<script>
import B from './B.vue'
export default {
name:'A',
components:{
B
},
data(){
return {
}
}
}
</script>
上面的例子,组件渲染时,子组件的 <slot></slot>
会被替换成123(即指定内容);
插槽内可以包含任何模板代码,包括HTML;也可以放其他组件。
3.1.2 后备(默认)内容
有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在父组件没有提供内容的时候被渲染。
在B组件中占位并写入后备内容:
<template>
<div>
<slot><p>我是B组件</p></slot>
</div>
</template>
当在父组件中不指定内容:
“我是B组件”会被渲染
当在父组件中指定内容:
<B>
<p>我是插槽内容</p>
</B>
则这个提供的后备内容将会被渲染从而取代后备内容:
3.2 具名插槽
具名插槽就是起了名字的插槽,有时我们需要多个插槽,例如,当我们想使用某种通用模板:
<!-- B.vue -->
<template>
<div>
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
一个不带 name 的
slot
出口会带有隐含的名字“default”,即匿名插槽。
在 向具名插槽提供内容 时,可以在一个 <template>
元素上使用 slot 指令,并以 slot 的参数的形式提供其名称(当然也可以直接放在标签中,如<div slot="header">
):
<!-- A.vue -->
<template>
<div>
<p>我是A组件</p>
<B>
<template slot="header">
<p>我是header部分</p>
</template>
<p>我是main(默认插槽)部分</p>
<template slot="footer">
<p>我是footer部分</p>
</template>
</B>
</div>
</template>
现在 <template>
元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有slot 的<template>
中的内容都会被视为默认插槽的内容。
页面效果:
3.3 作用域插槽
3.3.1 基本用法
让父组件在子组件的模板中可以访问子组件中的数据,通过作用域插槽可以获取到 row, column, $index 和 store(table 内部的状态管理)
的数据。
子组件:
<!-- B.vue -->
<template>
<div>
<p>我是B组件</p>
<!-- 绑定在插槽元素上的attribute为插槽prop -->
<slot :obj="obj">{{obj.firstName}}</slot>
</div>
</template>
<script>
export default {
name:'B',
data(){
return {
obj:{
firstName:'leo',
lastName:'lion'
}
}
}
}
</script>
父组件:
<template>
<div>
<p>我是A组件</p>
<B>
<template slot-scope="data">
{{data.obj.lastName}}
</template >
</B>
</div>
</template>
页面效果:
在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 data,但你也可以使用任意你喜欢的名字。
3.3.2 作用域插槽应用
1. 组件库中的使用
<el-table
v-loading="loading"
height="100%"
:data="resourceList"
>
<el-table-column
label="创建时间"
prop="createTime"
align="center"
width="180"
>
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column
label="操作"
align="center"
width="180"
>
<template slot-scope="scope">
<el-button type="text" @click="handleUpdate(scope.row)">编辑</el-button>
</template>
</el-table-column>
</el-table>
在父组件中使用 v-solt 或 slot-scope,可以访问到子组件中的数据;
父组件即这个页面组件,子组件即 el-table 组件;
:data="resourceList"会给到子组件一个数组数据集,slot-scope="scope"接收的值即是这个由子组件内部基于data生成出来的数据集。
通过 excel 描绘这个数据集:
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
常用:scope.row是行数据,scope.$index是行序号
2. 封装组件
sry。。还没封装过捏,待展开。。。
4. 总结
props 的设计思想是传递状态,子组件的渲染取决于父组件传递的数据;父组件在调用子组件的时候申明并赋值变量,那么子组件内将其加到 props 列表后,就可以接收并使用,但是一旦传递过来,作用域就发生变化;也就是说子组件中改变不影响父组件。
slot 的设计思想是传递 DOM 节点,将父组件的模板代码节点直接传递给子组件的某个 slot,来达到最终渲染的目的;子组件虽然为父组件预留 slot,但是 slot 的作用域依然属于父组件,所以可以访问到父组件内的所有状态;这里是说普通插槽子组件是在父组件中使用的,因此在模板中使用数据类似于作用域链,数据还是使用的父组件中的数据~
作用域插槽比较特殊,简单来说就是子组件提供给父组件的参数,该参数仅限于插槽中使用,父组件通过slot-scope
接收子组件传过来的插槽数据来进行不同的方式展现和填充插槽内容。