细谈Vue中插槽Slots


浅谈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插槽的同时,是可以传值的。给插槽上可以绑定数据,将来使用组件时可以用

  • 场景:封装表格组件

    1. 父传子,动态渲染表格内容
    2. 利用默认插槽,定制操作列
    3. 删除或查看都需要用到当前项的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'" 判断是否展示该内容。如果满足条件,则会显示对应元素。
  • 这样,根据表格数据和表头数据的不同,插槽内容会根据条件进行展示,可以自定义每个单元格的内容和交互行为。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会思想的苇草i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值