细谈Vue中插槽Slots
- 浅谈Vue中插槽Slots
- 1、默认插槽
- 2、后备内容
- 3、具名插槽
- 4、作用域插槽
- 5、代码实践
浅谈Vue中插槽Slots
<slot>
元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。- Vue 组件的插槽机制是受原生 Web Component
<slot>
元素的启发而诞生,同时还做了一些功能拓展 - vue的slot主要分三种,默认插槽,具名插槽,作用域插槽;使用插槽是在存在父子关系的组件中使用,我们可以在子组件中决定插槽的位置,同时子组件也可以给这些插槽的默认信息,当父组件中没有需要给子组件插槽插入信息时,显示的是子组件插槽定义的默认信息
- 插槽 Slots | Vue.js (vuejs.org)
1、默认插槽
- 作用:让组件内部的一些结构支持自定义
- 场景:将需要多次显示的对话框,封装成一个组件;组件的内容不希望写死,需要自定义。此时可以使用slot占位封装
-
插槽基本使用:
- 组件内需要定制的结构部分,改用
<slot></slot>
占位
<template> <slot></slot> </template>
- 使用组件时,
<MyDialog></MyDialog>
标签内部,传入结构替换slot
<MyDialog>success</MyDialog>
- 组件内需要定制的结构部分,改用
-
插槽内可以包含任何模板代码,包括HTML、组件
-
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的
2、后备内容
- 场景:通过插槽完成了内容的定制,传什么显示什么,但是如果不传,则是空白,此时可以给插槽设置默认显示内容
-
插槽后备内容(默认值)基本使用:
- 在
<slot></slot>
标签内放置内容,作为默认显示内容
<template> <slot>默认文本</slot> </template>
- 外部使用组件时,不传东西,则slot会显示后备内容
- 外部使用组件时,传东西了,则slot整体会被换掉
- 在
3、具名插槽
- 场景:一个组件内有多处结构,需要外部传入标签,进行定制
-
vue 2.6.0 版本使用具名插槽和作用域插槽有了新的统一语法,使用v-slot替换了之前的slot和slot-scope
-
具名插槽基本使用:
- 多个slot使用name属性区分名字
<slot name="head"></slot>
- template配合v-slot:名字来分发对应标签
<template v-slot:head> 文本 </template> //动态插槽名 <template v-slot:[dynamicSlotName]> 文本 </template> //简化写法 <template #head> 文本 </template>
-
如果一个
<slot>
不带name
属性的话,那么它的name
默认为default
-
一般情况下,
v-slot
只能添加在一个<template>
上
4、作用域插槽
-
作用:定义 slot插槽的同时,是可以传值的。给插槽上可以绑定数据,将来使用组件时可以用
-
场景:封装表格组件
- 父传子,动态渲染表格内容
- 利用默认插槽,定制操作列
- 删除或查看都需要用到当前项的id,属于组件内部的数据通过作用域插槽传值绑定,进而使用
-
作用域插槽基本使用:
- 给slot标签,以添加属性的方式传值
<slot :id="item.id" msg=“测试文本"></slot>
- 所有添加的属性,都会被收集到一个对象中
{ id: 3,msg:"测试文本’}
- 在template中,通过
#插槽名= "obj"
接收,默认插槽名为default
<MyTable :list="list"> <template v-slot:default="obj"> <button @click="del(obj.id)">删除</button> </template> </MyTable>
-
解构插槽:
<MyTable :list="list">
<template v-slot:default={id}>
<button @click="del(id)">删除</button>
</template>
</MyTable>
- prop重命名:
<MyTable :list="list">
<template v-slot:default={id:messageId}>
<button @click="del(messageId)">删除</button>
</template>
</MyTable>
- prop赋值(定义后备内容):
<MyTable :list="list">
<template v-slot:default="{id={messageId:1}}">
<button @click="del(messageId)">删除</button>
</template>
</MyTable>
5、代码实践
- 在实际项目中刚好有遇到使用slot的场景,这里结合实际项目进行具体分析,代码主体内容如下:
<!-- tableConfig.js -->
<template>
<!-- 表格数据 -->
<el-table :data="tableData">
<!-- 表头数据 -->
<el-table-column
v-for="(item, index) in tableHeader"
:label="item.text"
:prop="item.prop"
:key="index"
>
<template slot-scope="scope">
<!-- 具名作用域插槽 命名为detail 传递单行表格数据 表头数据 类型(父组件传入)-->
<slot name="detail" :data="scope.row" :item="item" :type="type">
<div>
<!-- 后置内容 展示表格文本数据 -->
<span
class="row-span"
v-html="
scope.row[item.prop] !== '' && scope.row[item.prop] !== null
? scope.row[item.prop]
: '-'
"
></span>
</div>
</slot>
</template>
</el-table-column>
</el-table>
<!-- 表格分页 -->
<el-pagination></el-pagination>
</template>
- 这段代码使用了 Element UI 的表格组件的模板,用于展示表格数据和表头数据
- 首先,通过
:data="tableData"
将表格数据传递给el-table
组件,其中tableData
是一个包含实际数据的数组。 - 然后,使用
v-for
循环遍历tableHeader
数组生成表头列。在每个表头列中,使用:label="item.text"
将表头文本显示出来,使用:prop="item.prop"
绑定对应数据字段的值。 - 接下来,使用
<template slot-scope="scope">
定义一个插槽,命名为detail
。在这个插槽中,通过:data="scope.row"
将单行的表格数据传递给插槽,通过:item="item"
将表头数据传递给插槽,通过:type="type"
将类型(在父组件中传入)传递给插槽。 - 在插槽的内容中,首先展示了表头数据,通过
v-html
属性将scope.row[item.prop]
的值渲染为 HTML。如果该值不为空或不为 null,则展示该值;否则展示-
。 - 这样,就可以在父组件中使用该模板,并利用插槽来自定义每个表格单元格的内容。具体的自定义内容可以在插槽的位置进行添加。
<!-- index.vue -->
<config-table :table-header="recordListHeader" :table-data="recordListData">
<!-- 插槽内容 -->
<template v-slot:detail="slotProps">
<!-- 判断是否展示 -->
<div v-if="slotProps.item.prop === 'OPERATE'">
<!-- HTML -->
<p v-if="slotProps.type !== 'master'" class="gameConfig_table_config_text"
@click="handleEditDetail(slotProps.data, slotProps.data.$index)">
切换所属游戏</p>
<p class="gameConfig_table_config_text" @click="handleEditProperty(slotProps.data, slotProps.data.$index)">
编辑游戏内容</p>
</div>
<!-- 判断是否展示 -->
<div v-else-if="slotProps.item.prop === 'list'">
<!-- 组件 -->
<game-and-icon-column
style="cursor: pointer;text-align: left;"
:key="index"
v-for="(item, index) in slotProps.data.list"
:appData="item"
@click.native="toDetail(item, slotProps.type)"
/>
</div>
</template>
</config-table>
- 这段代码是在使用
<config-table>
组件时,在组件内部定义了一个名为detail
的插槽,并提供了插槽内容。 - 首先,通过
:table-header="recordListHeader"
和:table-data="recordListData"
将表头数据和表格数据传递给<config-table>
组件。 - 然后,在
<config-table>
组件中,通过<template v-slot:detail="slotProps">
定义了一个名为detail
的插槽,并将插槽的 props 绑定到slotProps
对象上。 - 在插槽的内容中,首先通过
v-if="slotProps.item.prop === 'OPERATE'"
判断是否展示该内容(根据表头列的属性prop
来判断)。如果满足条件,则会显示对应元素。 - 在插槽内容的其余部分,通过
v-else-if="slotProps.item.prop === 'list'"
判断是否展示该内容。如果满足条件,则会显示对应元素。 - 这样,根据表格数据和表头数据的不同,插槽内容会根据条件进行展示,可以自定义每个单元格的内容和交互行为。
先通过v-if="slotProps.item.prop === 'OPERATE'"
判断是否展示该内容(根据表头列的属性prop
来判断)。如果满足条件,则会显示对应元素。 - 在插槽内容的其余部分,通过
v-else-if="slotProps.item.prop === 'list'"
判断是否展示该内容。如果满足条件,则会显示对应元素。 - 这样,根据表格数据和表头数据的不同,插槽内容会根据条件进行展示,可以自定义每个单元格的内容和交互行为。