vue+elementUI实现表格组件的封装

效果图:
在这里插入图片描述
在这里插入图片描述

在父组件使用表格组件
<table-list
          ref="table"
          :stripe="true"
          :loading="loading"
          :set-table-h="slotProps.setMainCardBodyH"
          :table-data="tableData"
          :columns="columns.tableList || []"
          :radio="topicTypeListMapItem.radio"
          show-opear
          show-selection
          :fix-width="240"
          :page-data="pageData"
          :disabled-select-key="topicTypeListMapItem.disabledSelectKey"
          @changeSize="changeSize"
          @changePage="changePage"
        >
          <!--预警灯-->
          <template #warningLight="{ row }">
            <div class="lightCireBlock">
              <div>
                <div v-for="(item,index) in row.warningLight" :key="'warningLight'+index">
                  <svg-icon v-if="Object.keys(columns.warningLight).includes(item)" :icon-class="columns.warningLight[item].icon" class="task-icon" />
                  <span
                    v-if="columns.warningLight[item] && columns.warningLight[item].hasNum && row[`warningLight${item}`] * 1 > 0"
                    class="fontBoxAll fontBox"
                  >{{ row[`warningLight${item}`] }}</span>
                </div>
              </div>
            </div>
          </template>
          <!--标题-->
          <template #taskTitle="{ row }">
            <span class="td-cell lineCell" @click="editMainEvent(row)"> {{ row.taskTitle }}</span>
          </template>
          <!--状态-->
          <template #status="{ row }">
            <el-tag :disable-transitions="true" :class="columns.statusLists[row.status].className">{{ columns.statusLists[row.status].label }}</el-tag>
          </template>
          <!--操作-->
          <template slot-scope="{ row }">
            <div class="table-buttonList">
              <template v-for="(item,index) in columns.btnList">
                <el-button
                  v-if="item.isShow?item.isShow(row):true"
                  :key="index"
                  type="text"
                  @click="btnFn[item.clickFn.fn](row,...(item.clickFn.params?item.clickFn.params:[]))"
                >{{ item.name }}</el-button>
              </template>
            </div>
          </template>
        </table-list>

然后用一个js文件来存储动态的参数

import { selectOverseerMeetingLeaType } from '@/api/common.js'

export const topicTypeListMap = new Map([
  [
    'keyWork',
    {
      name: '重点工作',
      radio: false, // 表格数据是否单选
      showImportBtn: true, // 是否显示批量导入按钮
      showApprovalBtn: false, // 是否显示送立项按钮
      showImportApprovalBtn: false, // 导入时是否显示送立项按钮
      showItemTypeBtn: false, // 导入时是否显示选择事项类型按钮
      showWorkRequireBtn: false, // 导入时是否显示批量填写工作要求按钮
      showFoliCureBtn: false, // 是否显示送办理按钮
      hasSubtasks: true, // 专题是否有子任务
      isMeetingTopicType: false, // 是否是会议类专题
      disabledSelectKey: [{ label: 'status', value: '0' }, { label: 'status', value: '1' }] // 表格哪些状态的数据禁选
    }
  ],
  [
    'feasibleInstructions',
    {
      name: '督办件',
      radio: false,
      showImportBtn: true,
      showApprovalBtn: true,
      showImportApprovalBtn: true, // 导入时是否显示送立项按钮
      showItemTypeBtn: true, // 导入时是否显示选择事项类型按钮
      showWorkRequireBtn: false, // 导入时是否显示批量填写工作要求按钮
      showFoliCureBtn: true,
      hasSubtasks: false,
      isMeetingTopicType: false,
      disabledSelectKey: []
    }
  ]

])

在组件中

props传的参数

props: {
    // 表格数据
    tableData: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 表格字段
    columns: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 表格字段的宽度
    fixWidth: {
      type: Number,
      default: 150
    },
    // 单选
    radio: {
      type: Boolean,
      default: false
    },
    // 显示序号
    showIndex: {
      type: Boolean,
      default: false
    },
    // 是否自定义高度
    setTableH: {
      type: Boolean,
      default: true
    },
    // 显示勾选
    showSelection: {
      type: Boolean,
      default: false
    },
    // 显示操作
    showOpear: {
      type: Boolean,
      default: false
    },
    spanMethod: {
      type: Function,
      default() {
        return () => {}
      }
    },
    // 斑马线
    stripe: {
      type: Boolean,
      default: false
    },
    // 分页
    showPagination: {
      type: Boolean,
      default: true
    },
    setCheckbox: {
      type: Boolean,
      default: false
    },
    loading: { // 判断是否正在加载表格数据
      type: Boolean,
      default: false
    },
    align: {
      type: String,
      default: 'left'
    },
    recordCheck: { // 是否在翻页的时候记录之前选择的表格数据
      type: Boolean,
      default: true
    },
    // 分页数据
    pageData: {
      type: Object,
      default: () => {
        return {
          page: 1,
          rows: 15,
          pageSize: [15, 25, 35],
          total: 0
        }
      }
    },
    isImportData: { // 判断是否导入的数据
      type: Boolean,
      default: false
    },
    disabledSelectKey: { // 需要禁用的选择框的数据
      type: Array,
      default: () => {
        return []
      }
    }
  },

完整代码

<template>
  <div ref="wrap" class="wrap">
    <el-table
      ref="table"
      :key="'tableData'+tableData.length"
      v-loading="loading"
      element-loading-text="正在处理,请稍候!"
      :data="tableData"
      :stripe="stripe"
      :span-method="spanMethod"
      :header-row-class-name="headerRowClassName(radio)"
      :height="setTableH?setTableHeight:'100%'"
      class="table-list"
      border
      @sort-change="sortChange"
      @selection-change="handleSelectionChange"
    >
      <template slot="empty">
        <img src="@/assets/images/empty.png">
        <p>暂无数据</p>
      </template>

      <!--选择框-->
      <el-table-column v-if="showSelection" type="selection" width="42" :selectable="checkSelectable" />
      <!--序号-->
      <el-table-column v-if="showIndex" type="index" label="序号" width="55" align="center" />
      <el-table-column
        v-for="item in columns"
        :key="item.lable"
        :label="item.title"
        :prop="item.slot || item.lable"
        :min-width="item.minWidth || 140"
        :width="item.width"
        :sortable="item.sortable"
        :show-overflow-tooltip="item.overflow"
        :align="item.align"
      >
        <!-- 二级表头 -->
        <el-table-column
          v-for="subItem in item.columns"
          :key="subItem.label"
          :label="subItem.title"
          :prop="subItem.slot || subItem.lable"
          :min-width="subItem.minWidth || 140"
          :width="subItem.width"
          :sortable="subItem.sortable"
          :show-overflow-tooltip="subItem.overflow"
          :align="subItem.align"
        >
          <template slot="header">
            <!-- <span v-if="item.isRequest" style="color:red">*</span> -->
            <span> {{ subItem.title }}</span>
          </template>
          <template slot-scope="{ row }">
            <slot :name="subItem.slot" :row="row">
              <span class="td-cell"> {{ isImportData ? row[subItem.label].value : row[subItem.label] }}</span>
              <template v-if="isImportData">
                <el-popover
                  v-if="typeof(row[subItem.label].success) === 'boolean' && !row[subItem.label].success"
                  placement="top"
                  title=""
                  trigger="hover"
                  :content="row[subItem.label].message"
                >
                  <i slot="reference" class="el-icon-warning" style="color:#F44336" />
                </el-popover>
              </template>
            </slot>
          </template>
        </el-table-column>
        <template slot="header">
          <!-- <span v-if="item.isRequest" style="color:red">*</span> -->
          <span> {{ item.title }}</span>
        </template>
        <template slot-scope="{ row }">
          <slot :name="item.slot" :row="row">
            <span class="td-cell">{{ isImportData ? row[item.label].value : row[item.label] }}</span>
            <template v-if="isImportData">
              <el-popover
                v-if="typeof(row[item.label].success) === 'boolean' && !row[item.label].success"
                placement="top"
                title=""
                trigger="hover"
                :content="row[item.label].message"
              >
                <i slot="reference" class="el-icon-warning" style="color:#F44336" />
              </el-popover>
            </template>
          </slot>
        </template>
      </el-table-column>

      <!--操作按钮-->
      <el-table-column v-if="showOpear" label="操作" prop="operation" :width="fixWidth" fixed="right">
        <template #default="{ row, $index }">
          <slot :row="row" :$index="$index" />
        </template>
      </el-table-column>

    </el-table>
    <el-pagination
      v-if="showPagination && tableData.length>0"
      background
      :current-page="pageData.page"
      :page-size="pageData.rows"
      :page-sizes="pageData.pageSize"
      layout="sizes, prev, pager, next, slot, jumper"
      :total="pageData.total"
      class="pagination"
      @current-change="handleCurrentChange"
      @size-change="handleSizeChange"
    >
      <span class="pagination-total">{{ pageData.total }}条,</span>
    </el-pagination>
  </div>
</template>

<script>
import { clone } from 'lodash'
export default {
  name: 'TableList',
  props: {
    // 表格数据
    tableData: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 表格字段
    columns: {
      type: Array,
      default: () => {
        return []
      }
    },
    // 表格字段的宽度
    fixWidth: {
      type: Number,
      default: 150
    },
    // 单选
    radio: {
      type: Boolean,
      default: false
    },
    // 显示序号
    showIndex: {
      type: Boolean,
      default: false
    },
    // 是否自定义高度
    setTableH: {
      type: Boolean,
      default: true
    },
    // 显示勾选
    showSelection: {
      type: Boolean,
      default: false
    },
    // 显示操作
    showOpear: {
      type: Boolean,
      default: false
    },
    spanMethod: {
      type: Function,
      default() {
        return () => {}
      }
    },
    // 斑马线
    stripe: {
      type: Boolean,
      default: false
    },
    // 分页
    showPagination: {
      type: Boolean,
      default: true
    },
    setCheckbox: {
      type: Boolean,
      default: false
    },
    loading: { // 判断是否正在加载表格数据
      type: Boolean,
      default: false
    },
    align: {
      type: String,
      default: 'left'
    },
    recordCheck: { // 是否在翻页的时候记录之前选择的表格数据
      type: Boolean,
      default: true
    },
    // 分页数据
    pageData: {
      type: Object,
      default: () => {
        return {
          page: 1,
          rows: 15,
          pageSize: [15, 25, 35],
          total: 0
        }
      }
    },
    isImportData: { // 判断是否导入的数据
      type: Boolean,
      default: false
    },
    disabledSelectKey: { // 需要禁用的选择框的数据
      type: Array,
      default: () => {
        return []
      }
    }
  },
  data() {
    return {
      saveMultipleSelection: {}, // 用来保存每个分页勾选的数据
      multipleSelection: [],
      setTableHeight: 300
    }
  },
  computed: {
    headerRowClassName() {
      return (radio) => {
        if (radio) {
          return 'tableHead isRadio'
        } else {
          return 'tableHead'
        }
      }
    }
  },
  watch: {
    tableData: {
      handler(newVal) {
        this.$nextTick(() => {
          if (this.multipleSelection && this.recordCheck) {
            const idList = this.multipleSelection.map(item => { return item.businessKey })
            newVal.forEach(item => {
              if (idList.indexOf(item.businessKey) > -1) {
                this.$refs.table.toggleRowSelection(item, true)
              }
            })
          }
        })
      },
      deep: true
    },
    saveMultipleSelection: {
      handler(newVal) {
        this.multipleSelection = Object.keys(newVal).reduce((prev, next) => {
          prev = prev.concat(newVal[next])
          return [...new Set(prev)]
        }, [])
        this.$EventBus.$emit('selection-change', this.multipleSelection)
      },
      deep: true
    }
  },
  updated() {
    this.$nextTick(() => {
      this.setTableHeight = this.$refs.wrap.offsetHeight - document.querySelector('.el-table__header-wrapper').offsetHeight - 48 - 10
      // 10是给分页腾一点空间
    })
  },
  methods: {
    handleSizeChange(e) {
      this.$emit('changeSize', e)
    },
    handleCurrentChange(e) {
      this.$emit('changePage', e)
    },
    clearSort() {
      this.$refs.table.clearSort()
    },
    getSelection() {
      return clone(this.$refs.table.selection)
    },
    sortChange(e) {
      this.$emit('sortChange', e)
    },
    checkSelectable(row) {
      let check = true
      if (this.disabledSelectKey.length > 0) {
        this.disabledSelectKey.forEach(item => {
          if (row[item.label] === item.value) {
            check = false
          }
        })
      }
      return check
    },
    handleSelectionChange(val) {
      if (this.radio) { // 单选
        // var newRows = val.filter((it, index) => {
        //   if (index === val.length - 1) {
        //     this.$refs.table.toggleRowSelection(it, true)
        //     return true
        //   } else {
        //     this.$refs.table.toggleRowSelection(it, false)
        //     return false
        //   }
        // })
        // this.saveMultipleSelection = newRows
        this.$nextTick(() => {
          var newRows = val.filter((it, index) => {
            if (index === val.length - 1) {
              this.$refs.table.toggleRowSelection(it, true)
              return true
            } else {
              this.$refs.table.toggleRowSelection(it, false)
              return false
            }
          })
          if (val.length > 0) {
            this.saveMultipleSelection = {}
            this.$set(this.saveMultipleSelection, this.pageData.page, newRows)
          }
          // this.saveMultipleSelection = newRows
        })
      } else {
        this.$nextTick(() => {
          this.$set(this.saveMultipleSelection, this.pageData.page, val)
        })
      }
    },
    toggleRowSelection(row, bool) {
      this.$refs.table.toggleRowSelection(row, bool)
    }
  }

}
</script>
<style scoped lang="scss">
   .wrap{
     height: 100%;
      ::v-deep .isRadio {
        .el-checkbox{
          display: none;
        }
      }
   }
   ::v-deep .el-table ::-webkit-scrollbar{
      height: 8px;
    }
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/521814.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

重磅!天途推出平安校园管理平台

天途平安校园管理平台&#xff0c;是围绕校园安全事件开发的一款智能监控与巡逻系统。系统通过大疆机场、无人机和校园内的监控硬件等多端传输的视频和图片信息&#xff0c;经过 AI分析处理后形成告警信息并及时通知学校安保人员。 天途平安校园管理平台 平安校园管理平台优势 …

【深度学习】从基础原理到未来挑战的全面探索

深度学习的基本原理 深度学习&#xff0c;一种模拟人脑分析和处理数据的机器学习技术&#xff0c;已成为人工智能研究中最令人兴奋的进展之一。其核心在于构建和训练神经网络&#xff0c;这些网络由多个层次组成&#xff0c;每一层都能从输入数据中提取并转换特征。随着数据层层…

[Java线程池]ExecutorService|CompletionService的区别与选择

这段时间对业务系统做了个性能测试&#xff0c;其中使用了较多线程池的技术&#xff0c;故此做一个技术总结。 这次总结的内容比较多&#xff0c;主要是四个&#xff1a; ExecutorServiceCompletionServiceRunnableCallable 前两个是线程池相关接口&#xff0c;后两个是多线…

《手把手教你》系列基础篇(七十四)-java+ selenium自动化测试-框架设计基础-TestNG实现DDT - 上篇(详解教程)

1.简介 上一篇文章中宏哥简单的讲解了一下通过xml文件传递参数&#xff0c;这一篇宏哥讲解通过通过DataProvider传递参数&#xff0c;也就是我们常说的数据驱动测试。如何利用TestNG实现DDT&#xff08;数据驱动测试 Data Driver Test&#xff09;&#xff0c;什么是数据驱动测…

椋鸟数据结构笔记#8:二叉树的遍历、创建与销毁

萌新的学习笔记&#xff0c;写错了恳请斧正。 链式二叉树 这篇笔记我们讨论基于链式二叉树&#xff0c;其节点的数据结构如下&#xff1a; typedef int BTDatatype;typedef struct BTNode {BTDataType data;struct BTNode* left;struct BTNode* right; } BTNode;二叉树的遍历…

STM32CubeMX配置步骤详解六 —— 时钟及其它内部参数配置(1)

接前一篇文章&#xff1a;STM32CubeMX配置步骤详解五 —— 基础配置&#xff08;2&#xff09; 本文内容主要参考&#xff1a; STM32CUBEMX配置教程&#xff08;一&#xff09;基础配置-CSDN博客 野火STM32系列HAL库开发教程 —— 第12讲 STM32的复位和时钟控制&#xff08;第…

环形链表 - LeetCode 热题 25

大家好&#xff01;我是曾续缘&#x1f970; 今天是《LeetCode 热题 100》系列 发车第 25 天 链表第 4 题 ❤️点赞 &#x1f44d; 收藏 ⭐再看&#xff0c;养成习惯 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可…

2-3 AUTOSAR ASW Runable可运行实体

返回总目录->返回总目录<- 目录 一、概述 二、RTE Event 一、概述 运行实体(Runnable Entity,RE)是一段可执行的代码,其包含实际实现的函数(具体的逻辑算法或者操作)。一个软件组件可以包含一个或者多个运行实体。 Runnable就是SWC中的函数,而在AutoSAR架构在被…

【云计算】云数据中心网络(一):VPC

云数据中心网络&#xff08;一&#xff09;&#xff1a;VPC 1.什么是 VPC2.VPC 的组成2.1 虚拟交换机2.2 虚拟路由器 3.VPC 网络规划3.1 VPC 数量规划3.2 交换机数量规划3.3 地址空间规划3.4 不同规模企业地址空间规划实践 4.VPC 网络高可靠设计4.1 单地域单可用区部署4.2 单地…

[StartingPoint][Tier1]Funnel

Task 1 How many TCP ports are open? (打开了多少个 TCP 端口&#xff1f;) # nmap -sS -T4 10.129.224.226 --min-rate 1000 2 Task 2 What is the name of the directory that is available on the FTP server? (FTP 服务器上可用的目录名称是什么&#xff1f;) $ n…

爬虫 新闻网站 以湖南法治报为例(含详细注释,控制台版) V3.0 升级 自定义查询关键词、时间段、粗略判断新闻是否和优化营商环境相关,避免自己再一个个判断

目标网站&#xff1a;湖南法治报 爬取目的&#xff1a;为了获取某一地区更全面的在湖南法治报的已发布的和优化营商环境相关的宣传新闻稿&#xff0c;同时也让自己的工作更便捷 环境&#xff1a;Pycharm2021&#xff0c;Python3.10&#xff0c; 安装的包&#xff1a;requests&a…

强力推荐一款具有故障保护和CAN FD 功能的隔离CAN收发器 SiLM5150S

控制器局域网总线(CAN&#xff0c;Controller Area Network)&#xff0c;是一种用于实时应用的串行通讯协议总线&#xff0c;它可以使用双绞线来传输信号&#xff0c;是目前应用最广泛的现场总线之一。CAN协议具有实时性强、可靠性高、传输距离远的特点&#xff0c;适用于各种复…

Python中定时任务调度利器APScheduler

在Python开发中&#xff0c;经常需要执行一些定时任务&#xff0c;比如定期发送邮件、定期更新数据等。APScheduler&#xff08;Advanced Python Scheduler&#xff09;是一个强大且易用的Python库&#xff0c;专门用于定时任务调度。它提供了丰富的调度接口&#xff0c;使得定…

51单片机学习笔记14 LCD1602显示屏使用

51单片机学习笔记14 LCD1602显示屏使用 一、LCD1602介绍1. 简介2. 引脚定义3. DDRAM4. 字模5. 指令&#xff08;1&#xff09;清屏指令 0x01&#xff08;2&#xff09;光标归位指令 0x02&#xff08;3&#xff09;进入模式设置指令 0x06&#xff08;4&#xff09;显示开关控制指…

短毛猫也能吃得好!揭秘宠物店推荐猫粮的秘密!

短毛猫通常毛发短而浓密&#xff0c;性格温顺&#xff0c;容易打理。那么&#xff0c;对于我们这些爱护短毛猫的朋友们来说&#xff0c;选择一款合适的猫粮就显得尤为重要了。今天&#xff0c;我要向大家推荐一款我个人非常喜欢的猫粮——福派斯三文鱼益生菌猫粮。 &#x1f41…

SAP操作教程第7期:SAP B1日期偏离允许范围解决方法

作为一种灵活的工具&#xff0c;自定义能够充分满足企业多样的需求。它允许你根据个人或团队的具体需求和情况来调整计划。通过自定义&#xff0c;你可以根据优先级、时间表、资源分配和风险管理等因素&#xff0c;制定更具体、实用的计划。 下面我们将详细探讨在SAP Business …

ARM_04

1.总结二进制信号量和计数型信号量的区别&#xff0c;以及他们的使用场景。 二进制信号量&#xff1a;只有0和1&#xff0c;一般用于资源共享时使用 计数型信号量&#xff1a;值一般是大于等于2的&#xff0c;可以实现同步互斥作用 2.使用技术型信号量完成生产者和消费者模型…

vue快速入门(九)事件绑定参数传递

注释很详细&#xff0c;直接上代码 上一篇 新增内容 事件绑定基础模板事件传参方法 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

蓝桥杯嵌入式(G431)备赛笔记——LED

目录 cubeMX配置&#xff1a; 代码模板&#xff1a; 注意&#xff1a; cubeMX配置&#xff1a; 原理图&#xff0c;其中PD2高电平使能锁存器&#xff0c;PC8-15默认给高电平&#xff0c;放置上电初始化LED亮 74HC573是八路输出锁存器 1脚是使能&#xff0c;低电平有效&#…

【JavaEE】浅谈线程(一)

线程 前言线程的由来线程是什么线程的属性线程更高效的原因举个例子&#xff08;线程便利性的体现&#xff09; 多线程代码线程并发执行的代码jconsole(观测多线程) 线程的调度问题创建线程的几种方法1&#xff09;通过继承Thread 重写run2&#xff09;使用Runnable接口 重写ru…