vue2 el-table 封装

vue2 el-table 封装

  1. 在 custom 文件夹下面创建 tableList.vue
  2. 直接上代码(代码比较多,复制可直接用)
javascript 复制代码
<template>
  <div class="mp-list">
    <el-table
      ref="multipleTable"
      class="mp-custom-table"
      :data="tableData"    
      v-loading="fullLoading"
      :highlight-current-row="highlightCurrentRow"
      :row-class-name="rowClassName"
      :border="isBorder"
      :reserve-selection="false"
      @row-click="handleClickRow"
      @current-change="handleCurrentChange"
      :row-key="rowKey"
      :default-expand-all="defaultExpandAll"
      :expand-row-keys="expandRowKeys"
      @expand-change="expandChangeClick"
      @header-click="handleClickHeader"
      doLayout
      :stripe="true"
      :default-sort="defaultSort"
      @selection-change="handleSelectionChange"
      @filter-change="filterChangeFn"
      @row-dblclick="ondblclick"
      width="100%"
      :height="tableHeight"
      :max-height="maxHeight"
      @select="select"
      @select-all="selectAll"
      :header-cell-style="headerCellStyle"
      @cell-mouse-enter="cellMouseEnter"
      @cell-mouse-leave="cellMouseLeave"
      @sort-change="sortChange"
      :key="statusKey"
    >
      <el-table-column v-if="selecShow" :align="selecShowAlign" :selectable="selectable" type="selection" width="60"></el-table-column>
      <el-table-column v-if="needSerialNumber" type="index" :label="serialNumberName"></el-table-column>
      // 行详情插槽
      <template v-if="expand">
        <slot name="expand"></slot>
      </template>
      <!-- theadData 配置项加了showOverTip字段,控制当前列是否使用tooltip,不传默认原来true -->
      <template v-for="(item, idx) of theadData">
        <el-table-column
          :label="item.title"
          :width="item.width"
          :prop="item.field"
          :sortable="item.sortable"
          :key="`${item.field || item.prop}_${idx}`"
          :min-width="item.minWidth"
          :align="cellAlign"
          :class-name="item.highlight ? 'mp-highlight' : ''"
          :sort-by="item.sortBy"
          :filter-placement="'bottom'"
          :filters="item.filters"
          :filter-method="item.filterMethod"
          :filter-multiple="false"
          :columnKey="item.field"
          :sort-method="item.sortFn"
          :show-overflow-tooltip="item.showOverTip !== undefined ? item.showOverTip : true"
        >
          <!-- 给列表的th添加提示icon,鼠标进过后显示tooltip,配置theadData时,配置headerTip内容,则展示到此,未配置不展示icon -->
          <template slot="header" v-if="item.headerTip">
            <span>
              {{ item.title }}
              <el-tooltip effect="dark" placement="top" :content="item.headerTip">
                <i class="el-icon-info"></i>
              </el-tooltip>
            </span>
          </template>

          <template slot-scope="scope">
            <slot v-if="item.isSlot" :name="item.field" :scope="scope" :row="scope.row" :column="scope.column" :store="scope.store" :_self="scope._self"></slot>
            <div v-else>
              <div v-if="item.htmlCustom && typeof item.htmlCustom === 'function'" v-html="item.htmlCustom(scope.row, scope.column, scope.row[item.field], item.field) || '--'"></div>
              <span v-else>{{ fieldDeel(scope.row, item.field) || '--' }}</span>
            </div>
          </template>
        </el-table-column>
      </template>

      <template slot="empty">
        <div class="mp_tatble_nodata">
           // 表格数据为空时,显示暂无数据图片
           // 图片根据自己的主题,更换合适的图片
          <img class="mp_noData_image" src='/img/dark_no_data.png' alt />
          <p class="mp_tatble_txt">暂无数据</p>
        </div>
      </template>

      <slot name="slotTip"></slot>
      <slot name="operbtn"></slot>
			<!-- other 是为了处理表格列key在某个子对象下,父组件正常循环 -->
			<slot name="other"></slot>
    </el-table>
  </div>
</template>

<script>
export default {
  name: 'tableList',
  props: {
    //表格高亮当前选中行
    highlightCurrentRow: {
      default: false,
    },
    expand: {
      type: Boolean,
      default: false,
    },
    rowKey: {
      type: String,
      default: 'id',
    },
    expandRowKeys: {
      type: Array,
      default: () => [],
    },
    // table高度,接收String
    tableHeight: {
      default: false,
    },
    maxHeight: {
      type: String,
      default: '100%',
    },
    tableData: Array, // 表格内容
    theadData: {
      type: Array,
    }, // 表头内容
    fullLoading: Boolean, // 加载遮罩
    sid: String,
    selecShow: {
      // 是否有选择框
      type: Boolean,
      default: false,
    },
    selecShowAlign: {
      type: String,
      default: 'left'
    },
    isBorder: {
      type: Boolean,
      default: true,
    },
    bk_obj_name: '',
    cellAlign: {
      type: String,
      default: 'left',
    },
    //设置表头样式
    headerCellStyle: {
      type: Object,
    },
    serialNumberName: {
      type: String,
      default: '序号',
    },
    needSerialNumber: {
      type: Boolean,
      default: false,
    },
    defaultExpandAll: {
      type: Boolean,
      default: false,
    },
    // 默认排序
    defaultSort: {
      type: Object,
      default: {
        prop: 'date',
      },
    },
    rowClassName: {
      type: Function,
    },
  },

  data() {
    return {
      idSelection: [],
      statusKey: 0,
    }
  },
  created() {},
  methods: {
    fieldDeel(row, field) {
      let arr = field.split('.')
      let text = row
      arr.forEach((item) => {
        text = text[item]
      })
      if (text == 0) {
        text = text + ''
      }
      return text
    },
    handleClickHeader(col, e) {
      // 点击某一表头
      if (col && col.sortable) {
      }
    },
    filterChangeFn(filter) {
      if (typeof this.$parent.getFilterValueFn === 'function') {
        this.$parent.getFilterValueFn(filter)
      }
    },
    handleClickRow(row, col, e) {
      //点击某一行跳转
      if (col && col.className) {
        if (col.className == 'mp-highlight') {
          this.$emit('handleClickRow', row, col, this.bk_obj_name)
        }
      }
    },
    ondblclick(row, col, e) {
      // 某一行的双击事件
      this.$emit('ondblclick', row, col)
    },
    toggleSelection(rows, selected) {
      this.$nextTick(() => {
        if (rows) {
          rows.forEach((row) => {
            this.$refs.multipleTable.toggleRowSelection(row, selected)
          })
        } else {
          this.$refs.multipleTable.clearSelection()
        }
      })
    },
    // 单行设置高亮
    setCurrentRowHandel(row) {
      this.$nextTick(() => {
        this.$refs.multipleTable.setCurrentRow(row[0])
      })
    },
    refreshLayout() {
      this.$nextTick(() => {
        this.$refs.multipleTable.doLayout()
      })
    },
    // 展开航
    expandChangeClick(row, expandRow) {
      this.$emit('expandChange', row, expandRow)
    },
    handleSelectionChange(val) {
      // 多选
      this.idSelection = []
      val.forEach((item) => {
        this.idSelection.push(item[this.sid])
      })
      this.$emit('changeData', this.idSelection, val)
      this.$emit('queryRow', val)
    },
    selectable(row, index) {
      // 是否禁用多选
      let state = true
      if (row.typeFlagOrganization) {
        state = !row.typeFlagOrganization
      }
      return state
    },
    // 手动勾选数据行的 Checkbox 时触发的事件
    select(selection, row) {
      this.$emit('select', selection, row)
    },
    selectAll(selection) {
      this.$emit('select-all', selection)
    },
    cellMouseEnter(row, column, cell, event) {
      this.$emit('cell-mouse-enter', { row, column, cell, event })
    },
    cellMouseLeave(row, column, cell, event) {
      this.$emit('cell-mouse-leave', { row, column, cell, event })
    },
    // 点击表格行时选中
    handleCurrentChange(row) {
      // this.$refs.multipleTable.toggleRowSelection(row)
      if (this.highlightCurrentRow) {
        //有高亮效果可单选 ---平面图资产关联使用
        this.$emit('handleCurrentChange', row)
      }
    },
    formatterCellval(row, column, cellValue, index) {
      // 没有内容时的占位符,暂时无用
      if (typeof this.$parent.customFormatterCellval === 'function') {
        // 判断外部是否有customFormatterCellval方法
        const value = this.$parent.customFormatterCellval(row, column, cellValue, index)
        return value
      } else {
        // 没有-赋值给表格
        if (!Boolean(cellValue)) {
          return '--'
        } else {
          return cellValue
        }
      }
    },
    // 排序方法
    sortFn(a, b) {},
    // 监听排序事件
    sortChange(data) {
      this.$emit('sort-change', data)
    },
  },
  watch: {
    theadData: {
      handler(vv) {},
      deep: true,
    }
  },
}
</script>

<style>
.el-table__body-wrapper tr:hover .mp-highlight {
  color: #2579ff;
  cursor: pointer;
}

.el-tooltip__popper {
  max-width: 800px;
}

td.mp-highlight:hover {
  color: #2579ff;
  cursor: pointer;
}

.el-table__header thead th .cell .el-table__column-filter-trigger i.el-icon-arrow-down {
  position: absolute;
  top: 6px;
  left: auto;
  color: #666;
  transform: scale(1);
}

.el-table__header thead th .cell .el-table__column-filter-trigger i.el-icon-arrow-down:before {
  content: '\e790';
}

.mp-custom-table {
  font-size: 14px;
  /* border-radius:10px; */
}

.el-table__header-wrapper {
  border-radius: 0;
}

.el-table__header-wrapper .cell .el-icon-info {
  cursor: pointer;
  opacity: 0.4;
}
.el-table__header-wrapper .cell .el-icon-info:hover {
  opacity: 0.8;
}

/* .el-table__body-wrapper{
  border-radius:10px;
} */

.el-table--border th {
  border-right: none;
}

.el-table--border td {
  border-right: none;
}

.mp-custom-table .el-table--striped .el-table__body tr.el-table__row--striped td {
  background-color: RGBA(247, 248, 252, 1) !important;
}

.mp-list.mp-custom-table .el-table__body-wrapper tr:hover td {
  background-color: RGBA(231, 244, 255, 1) !important;
}

.mp-custom-table .el-table--border,
.el-table--group {
  border-left: none;
  border-right: none;
  border-top: none;
}

.mp-custom-table .el-table--border::after,
.el-table--group::after,
.el-table::before {
  background-color: transparent !important;
}

.mp-custom-table.el-table .el-table__body-wrapper {
  padding-bottom: 0px;
}

.mp-custom-table.el-table .el-table__fixed-right {
  height: calc(100% - 10px) !important;
}

.mp-custom-table.el-table .el-table__fixed-right::before {
  background-color: transparent !important;
}

.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar {
  width: 5px;
  height: 8px;
  background-color: #fff;
  border-radius: 5px;
  border-left: none;
}

.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar-track,
.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar-thumb {
  border-radius: 999px;
}

.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar-track {
  box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2) inset;
}

.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar-thumb {
  background-clip: content-box;
  background: rgba(0, 0, 0, 0.01);
  box-shadow: none;
}

/* .el-table.mp-custom-table
  .el-table__body-wrapper:hover::-webkit-scrollbar-thumb {
  background: red;
} */

.el-table.mp-custom-table .el-table__body-wrapper::-webkit-scrollbar-corner {
  background: transparent;
}

.mp_tatble_nodata {
  /* padding: 40px 0; */
  display: flex;
  align-items: center;
  flex-flow: column;
  justify-content: center;
}

.mp_noData_image {
  width: 80px;
  height: 80px;
}

.mp_tatble_txt {
  font-size: 14px !important;
}
</style>
<style>
.mp-list.mp-custom-table .el-table__header thead tr th {
  background: rgba(242, 244, 248, 1) !important;
  color: rgba(68, 79, 89, 1) !important;
}
.eveningTheme .el-table__body-wrapper tr:hover .mp-highlight {
  color: #07f6ff !important;
}
</style>
<style lang="scss" scoped>
.eveningTheme {
  .el-table__body-wrapper tr:hover .mp-highlight {
    color: #07f6ff !important;
  }
  .mp-custom-table ::v-deep .el-table__header thead tr th {
    background: #062540 !important;
    // color:#fff !important;
  }

  .mp-custom-table {
    ::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td {
      background-color: #062540 !important;
    }

    ::v-deep .el-table__body-wrapper tr:hover td,
    ::v-deep .el-table--striped .el-table__body tr.el-table__row--striped:hover td {
      background-color: #153864 !important;
    }

    ::v-deep .el-table__body-wrapper tr:hover .mp-highlight {
      color: #07f6ff;
      cursor: pointer;
    }

    ::v-deep td.mp-highlight:hover td {
      color: #07f6ff;
      cursor: pointer;
    }

    ::v-deep .el-table__body-wrapper {
      &::-webkit-scrollbar {
        width: 5px;
        height: 5px;
        background-color: transparent;
        border-radius: 5px;
        border-left: none;

        &-track {
          background-color: #020919;
        }

        &-thumb {
          background-color: #07639d;
        }
      }
    }

    ::v-deep .el-table__body-wrapper:hover {
      &::-webkit-scrollbar {
        &-thumb {
          background-color: #153864;
        }
      }
    }

    ::v-deep.el-table {
      tr {
        background-color: #020919 !important;
      }
    }
  }
}
::v-deep .mp-disabled-row,
::v-deep .mp-list.mp-custom-table .el-table__body-wrapper tr.mp-disabled-row:hover,
::v-deep .mp-custom-table .el-table--striped .el-table__body tr.el-table__row--striped.mp-disabled-row {
  td {
    //border-top: 1px dashed rgba(62, 127, 255, 1);
    border-bottom: 1px dashed rgba(62, 127, 255, 1);
    background: rgba(62, 127, 255, 0.2) !important;
  }
}
</style>
<style lang="scss">
.eveningTheme {
  .mp-list.mp-custom-table .el-table__header thead tr th {
    background: #071d30 !important;
    // color:rgba(68, 79, 89, 1) !important;;
  }
}
</style>
  1. 组件简单使用 (基本常用的属性方法都已封装进去 , 可自行查看 tableList.vue )
    (如果缺少需要的功能,可自行补充,或者留言)
javascript 复制代码
/**
 :selecShow="true"    // 开启复选框
 :tableData="dataTableListInfo"   // 表格数据
 :theadData="option.column"  // 表格头部
 :fullLoading="loading"  // 表格loading
 @queryRow="selectDataTable"  // 表格多选事件
 @handleClickRow="getHandleClickRow"  // 行点击事件

*/
<template>
	<div>
		<table-operation
		 class="mp-custom-table"
		 :selecShow="true"
		 :tableData="dataTableListInfo"
		 :theadData="option.column"
		 :fullLoading="loading"
		 @queryRow="selectDataTable"
		 @handleClickRow="getHandleClickRow"
		 ref="tableRef"
		>
		  // 该字段使用了插槽  对数据做了处理
		 <template slot="keyNode" slot-scope="{ row }">
		   <span>{{ row['keyNode'] == 1 ? '否' : '是' }}</span>
		 </template>
		 // 表格按钮组
		 <el-table-column slot="operbtn" label="操作" width="160" fixed="right">
		   <template slot-scope="{ row }">
		   <mp-button type="text" class="mp-button_edit-custom mp-button_table-typeA-custom" @click="editFormTable(row)">编辑</mp-button>
		     <mp-button type="text" class="mp-button_edit-custom mp-button_table-typeA-custom" @click="deleteFormTable(row)">删除</mp-button>
		   </template>
		 </el-table-column>
		</table-operation>
		// 分页组件
		 <mp-pagination :pageIndex="pageIndex" :pageSize="pageSize" :total="total" @page-change="pageChange" @page-size-change="pageSizeChange"></mp-pagination>
	</div>
</template>
<script>
import TableOperation from '@/custom/tableList' // 引入上面的表格组件
export default {
  components: {
    TableOperation,
  },
  data() {
    return {
      dataTableList: [],
      loading: false,
      pageIndex: 1, //页码
      pageSize: 10, //分页条目数
	  total: 0, // 总条数
      option: {
	    column: [
	      {
	        field: 'indexName',
	        highlight: true,  // 鼠标移入表格行后,指标名称字段高亮   点击指标名称 跳转
	        title: '指标名称', 
	        //  给列表的th添加提示icon,鼠标进过后显示tooltip,配置theadData时,配置headerTip内容,则展示到此,未配置不展示icon
	        headerTip: '检测内容定义的名称',
	      },
	      {
	        field: 'indexCode',
	        title: '唯一标识',
	        headerTip: 'cmdb 中字段唯一标识',
	      },
	      {
	        field: 'keyNode',
	        title: '是否关键指标',
	        headerTip: '标记',
	        // 该字段是否使用插槽
	        isSlot: true, //插槽
	      }
	    ],
	  }, // 表头
    }
  },
  methods:{
        // 编辑
        editFormTable(row){},
	    deleteFormTable(row) {
	      // 这里是表格行删除事件
	    },
	        // 多选
	    selectDataTable(row, data) {
	     
	    },
	    // 每一行的指标名称点击事件
	    getHandleClickRow(row) {
		   	
		},
		 // 分页
	    pageChange(pageIndex) {
	      this.pageIndex = pageIndex
	    },
	    // 分页每页条数
	    pageSizeChange(pageSize) {
	      this.pageIndex = 1
	      this.pageSize = pageSize
	    },
	}
}
</script>
  1. 效果

  2. 扩展(分页组件)

    1. 在 custom 文件夹下 新建 mpPagination.vue
    2. 上代码
javascript 复制代码
// mpPagination.vue

<template>
  <!-- 分页 -->
  <div class="avue-crud__pagination">
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="pageIndex"
      :page-sizes="pageSizeOption"
      :page-size="pageSize"
      :pager-count="showPagingCount"
      :layout="layout"
      :total="total"
      :key="keyIndex"
    >
    </el-pagination>
  </div>
</template>

<script>
export default {
  name: 'MpPagination',
  props: {
    index:{
      type:Number,
      default:0
    },
    //总条数
    total: {
      type: Number,
      default: 0,
    },
    //当前页
    pageIndex: {
      type: Number,
      default: 1,
    },
    //页码按钮的数量,当总页数超过该值时会折叠
    showPagingCount: {
      type: Number,
      default: 7,
    },
    //每页条目数
    pageSize: {
      type: Number,
      default: 10,
    },
    //配置功能布局
    layout: {
      type: String,
      default: 'total, sizes, prev, pager, next, jumper',
    },
    //选择每页条目数
    pageSizeOption: {
      type: Array,
      default() {
        return [10, 20, 50]
      },
    },
  },
  data() {
    return {
      keyIndex:0
    }
  },
  methods: {
    //每页条目数改变
    handleSizeChange(val) {
      this.$emit('page-size-change', val,this.index)
    },
    //当前页改变
    handleCurrentChange(val) {
      this.$emit('page-change', val,this.index)
    },
  },
}
</script>
  1. 以上为全部代码!
相关推荐
远山枫谷1 分钟前
🎉告别 Vuex!Vue3 状态管理利器 Pinia 核心概念与实战指南
前端·vue.js
张西餐2 分钟前
前端项目如何引入大语言模型
前端
光影少年4 分钟前
Vue组件通信方式?
前端·vue.js·掘金·金石计划
SuniaWang6 分钟前
Vue 项目 Docker 多阶段构建部署指南(阿里云)
vue.js·阿里云·docker
庄小焱11 分钟前
Vue——Vue基础语法(1)
前端·javascript·vue.js·前端框架
bigorangeqwq15 分钟前
灵机一动想看清全球媒体怎么报同一件事,我撸了个新闻分析站
前端
yangyanping2010819 分钟前
Vue入门到精通六之一个简单的请求HTTP接口
前端·vue.js·http
小圣贤君21 分钟前
在 Electron 里造一个「搜书 + 下载」:从 so-novel 到 51mazi 的爬虫实践
前端·人工智能·爬虫·electron·ai写作·小说下载·网文下载
淘源码d32 分钟前
基于Spring Boot + Vue的诊所管理系统(源码)全栈开发指南
java·vue.js·spring boot·后端·源码·门诊系统·诊所系统
weixin_4434785139 分钟前
flutter学习之状态管理相关组件
javascript·学习·flutter