vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件

CommTable.vue table组件

<template>
  <div>
    <el-table
      :data="tableData"
      border
      :class="tabClass ? tabClass : null"
      :showHeader="showHeader ? showHeader : true"
      :spanMethod="spanMethod ? spanMethod : null"
      element-loading-text="加载中..."
      v-loading="loading"
      :height="height ? height : null"
      :maxHeight="maxHeight ? maxHeight : null"
      :ref="tabRef ? tabRef : null"
      :header-cell-style="smallRow ? lineStyle : null"
      :cell-style="smallRow ? lineStyle : null"
      @sort-change="sortByKey"
      @selection-change="selectionChange"
      :row-key="rowKey ? rowKey : null"
    >
      <!-- 详情内容展示 需要showExpand属性  -->
      <el-table-column type="expand" v-if="showExpand">
        <template slot-scope="{ row }">
          <slot name="expand" :data="row"></slot>
        </template>
      </el-table-column>
      <!-- checkout复选框  selectionObj对象 { show: true, fixed: true}-->
      <el-table-column type="selection" align="center" width="50" v-if="selectionObj.show" :fixed="selectionObj.fixed ? true : false ">
      </el-table-column>
      <el-table-column
        v-for="({ prop, label, width, minWidth ,sortBy, slotName, countLimit, childrenList, className, columnFlag, fixed }, index) in tablecolumn"
        :key="index"
        :prop="prop ? prop : null"
        :label="label ? label : null"
        :width="width ? width : null"
        :min-width="minWidth ? minWidth : 100"
        :sort-by="sortBy ? sortBy : null"
        :sortable="sortBy ? (columnFlag ? 'column' : true) : null"
        :className="className ? className : null"
        :fixed="fixed ? fixed : null"
        :render-header="renderHeader ? renderHeader : null"
        align="center"
      >
      <!-- 自定义表头 -->
      <template  slot="header" >
        <slot v-if="slotName" :name="slotName+'Header'" ></slot>
      </template>
      <!-- 自定义内容 -->
      <template v-if="!childrenList" slot-scope="{row, $index}">
        <!-- 自定义tamplate -->
        <!-- prop没有值的情况 传整个row -->
        <div  v-if="slotName" >
          <slot :name="slotName" :data="prop ? row[prop] : null" :index="$index" :rowData="row"></slot>
        </div>
        <!-- 字数(countLimit控制)超出显示tip -->
        <div v-else>
          <div v-if="row[prop] && row[prop].length > (countLimit ? countLimit : 50)">
              <el-tooltip effect="dark" :content="row[prop]" placement="top" popper-class="tooltipsCont">
                  <span class="limitInfo">{ { row[prop] | textSubstr((countLimit ? countLimit : 50))}}</span>
              </el-tooltip>
          </div>
          <div  v-else>
              <span >{ { row[prop] | emptyText}}</span>
          </div>
        </div>
      </template>

      <!-- 如果有多组数据 注: 必传prop  childrenList为数据配置项 -->
      <el-table-column
      v-if="childrenList && childrenList.length > 0"
      v-for="(item, index) in childrenList"
      :label="item.label"
      :key="index"
      :width="width ? width : null"
      :min-width="minWidth ? minWidth : 100"
      align="center">
        <template slot-scope="{row, $index}">
           <!-- 自定义tamplate -->
          <div  v-if="slotName">
            <!-- 插槽传值 data:数组数据 prop:当前数组对象的key index:行索引 -->
            <slot  :name="slotName" :data="prop ? row[prop] : []" :prop="item.prop" :rowData="row" :index="$index"></slot>
          </div>
          <!-- 不是自定义默认遍历数据 row[prop] 获取数组 item.prop为数组配置项的prop -->
          <div v-else >
            <div class="flex-column">
              <div v-for="(dataItem, dataIndex) in row[prop]" :key="dataIndex">
                { { dataItem[item.prop]}}
              </div>
            </div>
          </div>
        </template>
      </el-table-column>
      </el-table-column>
    </el-table>
    <!-- 分页插槽 -->
    <slot name="el-pagination"></slot>
  </div>
</template>
<script>
import {  PropsType } from "../propsType.js";
import Sortable from "sortablejs";
export default { 
  name: "comm_table",
  data() { 
    return { 
      lineStyle:{ 
        'font-size': '14px',
        'height': '45px',
        'padding': '3px 0'
      },
    };
  },
  props: { 
    tableData: PropsType.Array,
    tablecolumn: PropsType.Array,
    loading: PropsType.Boolean,//loading
    showExpand: PropsType.Boolean,//是否展示详情行
    selectionObj: PropsType.Object,//是否展示详情行
    height: PropsType.Number,//表格高度
    maxHeight: PropsType.Number,//表格最大高
    tabRef:  PropsType.String,//表格ref
    smallRow: PropsType.Boolean,//控制表格行高
    showHeader: PropsType.Boolean,//是否显示表头
    spanMethod: PropsType.Function,//合并行合并列
    renderHeader: PropsType.Function,//自定义表头
    tabClass: PropsType.String,//表格class [拖动表格需要的参数]
    rowKey: PropsType.String,//表格唯一标识 [拖动表格需要的参数]
    dragTableFlag: PropsType.Boolean,//是否可拖动表格排序 [拖动表格需要的参数]
  },
  watch: { 
  },
  methods: { 
      sortByKey (column) { //排序
      let params = { }
      if(column.order){ 
        if (column.column) { 
          params.orderBy = column.column.sortBy
          params.desc = column.column.order === 'descending'
          params.order = true;
        }
      }else{ //排序恢复
        params.order = false;
      }
      // else { //自定义初始化排序 看情况传入
        //例如
        // params.orderBy = 'avgSales'
        // params.desc = true
      // }
      this.$emit('sortChange', params)
    },
    selectionChange(val) { // 表格checkbox 选择行回调
      this.$emit('selectionChange', val)
    },
    rowDrop() { 
      // 此时找到的元素是要拖拽元素的父容器
      const tbody = document.querySelector(`.${ this.tabClass} .el-table__body-wrapper tbody`);
      const _this = this;
      Sortable.create(tbody, { 
        // 指定父元素下可被拖拽的子元素
        draggable: ".el-table__row",
        onEnd({  newIndex, oldIndex }) { 
          if (newIndex !== oldIndex) { 
            const currRow = _this.tableData.splice(oldIndex, 1)[0];
            _this.tableData.splice(newIndex, 0, currRow);
            _this.$emit('getDragTableSort', _this.tableData);
          }
        },
      });
    },
  },
  filters: { 
    textSubstr (value, qtd = 50, mask = '...') { 
      if (!value) return '-';
      return value.length > qtd ? `${ value.substring(0, qtd)}${ mask}` : value
    },
    emptyText(value){ //数据为0的情况显示
      if(value === ''){ 
	 	  return '-'
	  }
      return value ?? '-'; //或者 (value !== undefined && value !== null) ? vaule : '-'
    }
  },
  mounted() { 
    this.dragTableFlag && this.rowDrop();
  },
};
</script>
<style lang="scss">
.tooltipsCont{ 
  max-width: 500px;
  max-height: 450px;
}
</style>
<style lang="scss" scoped>
.limitInfo{ 
  cursor: pointer;
}
.flex-column{ 
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>


组件中使用的 propsType.js

export const PropsType = { 
  Array: { 
    type: Array,
    default: ()=>([])
  },
  Object: { 
    type: Object,
    default: ()=>({ })
  },
  Boolean: { 
    type: Boolean,
    default: false,
  },
  String: { 
    type: String,
    default: ''
  },
  Number: { 
    type: Number,
    default: 0
  },
  Function: Function,
  Promise: Promise
}

如何使用CommTable组件【基本展示】

<template>
  <div class="content">
    <div>
      <h1>EC2</h1>
      <CommTable
        tabRef="ec2Table"
        :tableData="tableData"
        :height="450"
        :tablecolumn="tablecolumn"
        :loading="tableLoading"
        :smallRow="true"
        @sortChange="getSortParams"
      >
        <template v-slot:state="{data, index}">
          { { data ? '显示' : '隐藏'}}
        </template>
        <template v-slot:desired="{data, index}">
          { { desiredList.filter(e=>e.value===data)[0].label || '-'}}
        </template>
        <template v-slot:skuProductList="{data, index, prop}">
          <!-- prop是属性 data是当前值 -->
          <div class="flex-column">
            <span v-for="(item, itemIndex) in data" :key="itemIndex">
              { { item[prop]}}
            </span>
          </div>
        </template>
        <template v-slot:operate="{rowData, index}">
          <el-button @click="openEC2Dialog(rowData)" size="mini" type="primary">编辑</el-button>
        </template>
        <el-pagination slot="el-pagination" @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page.sync="pageNum" :page-sizes="[10, 15, 20, 30, 50]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
        </el-pagination>
      </CommTable>
    </div>
    <EC2Dialog :dialogVisible.sync="ec2visible" :rowObj="selectRow"></EC2Dialog>
  </div>
</template>
<script>
import CommTable from "src/components/partials/CommTable.vue";
import EC2Dialog from './components/editEC2Dialog.vue';
export default { 
  name: "operationManagement",
  components: { 
    CommTable,
    EC2Dialog
  },
  data() { 
    const skuProductColumn = [
        { prop: 'name', label: 'sku'},
        { prop: 'count', label: '数量'},
        { prop: 'price', label: '价格'},
      ];
    return { 
      tableData: [],
      tablecolumn: [
        {  prop: "id", label: "ID" },
        {  prop: "name", label: "名称" },
        {  prop: "state", label: "状态" , slotName: 'state'},
        {  prop: "instances", label: "实用类型" },
        {  prop: 'skuProductList',label: 'sku信息', slotName: 'skuProductList', minWidth: 200, childrenList: skuProductColumn},
        {  prop: "privateIPAddres", label: "私有IP地址", sortBy: "privateIPAddres", countLimit: 3, width: 120 },
        {  prop: "publicIPAddres", label: "公有IP地址" },
        {  prop: "functionDescription", label: "描述" },
        {  prop: "desired", label: "预期状态" ,slotName: 'desired'},
        {  prop: '', label: '操作', slotName: 'operate',}
      ],
	  desiredList: [
	  	{  value: 'stop', label: '停止' },
        {  value: 'delete', label: '删除' },
        {  value: 'start', label: '启动' },
      ],
      tableLoading: false,
      ec2visible: false,
      pageSize: 15,
      pageNum: 1,
      total: 0,
      selectRow: { }
    };
  },
  methods: { 
    initData() { 
      this.tableLoading = true;
      setTimeout(() => { this.tableLoading = false; this.tableData = [...Array(10).keys()].map((e) => ({ id: e, name: "name" + e, state: false, instances: "实用类型", privateIPAddres: "私有IP地址", publicIPAddres: "公有IP地址", functionDescription: "描述", desired: Math.random() > .5 ? 'stop' : 'delete', skuProductList: [ {name: 'H60523D1', count: 2, price: 39.99}, {name: 'H60523D2', count: 10, price: 5.99}, ] }));
        this.total = 10
      }, 1000);
    },
    openEC2Dialog(row) { 
      this.selectRow = Object.assign({ },row);
      console.log(this.selectRow,'selectRow')
      this.ec2visible = true;
    },
    getSortParams(params) { 
      console.log("sore", params);
    },
    handleCurrentChange(val) { 
      this.pageNum = val;
      this.initData();
    },
    handleSizeChange(val) { 
      this.pageSize = val;
      this.pageNum = 1;
      this.initData();
    },
  },
  mounted() { 
    this.initData();
  },
};
</script>
<style lang="scss" scoped>
.content { 
  padding: 20px;
}
.flex-column{ 
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
</style>

**column的配置项介绍 **

{ prop, label, width, minWidth ,sortBy, slotName, countLimit, childrenList, className, columnFlag, fixed }
prop: 字段值
label: 显示名称
…宽度
sortBy: 是排序 当有设置的时候 给定一个字符串 然后 就会通过事件返回这个字符串的排序对象参数
slotName : 是自定义字段 有时候表格内容可能需要改动 添加按钮什么的就需要添加这个
countLimit: 字段展示的字符数
childrenList: 数组数据配置 => [{prop:‘字段值’, label:‘表头’}];
className: 给列名添加类名
columnFlag: 区分前后台排序 默认为前台排序 为true时 后台排序
fixed: 定位

 tablecolumn: [
        {  prop: "id", label: "ID" },
        {  prop: "name", label: "名称" },
        {  prop: "state", label: "状态" , slotName: 'state'},
        {  prop: "instances", label: "实用类型" },
        {  prop: 'skuProductList',label: 'sku信息', slotName: 'skuProductList', minWidth: 200, childrenList: skuProductColumn},
        {  prop: "privateIPAddres", label: "私有IP地址", sortBy: "privateIPAddres", countLimit: 3, width: 120 },
        {  prop: "publicIPAddres", label: "公有IP地址" },
        {  prop: "functionDescription", label: "描述" },
        {  prop: "desired", label: "预期状态" ,slotName: 'desired'},
        {  prop: '', label: '操作', slotName: 'operate',}
      ],

我调用的时候 有些字段是自定义字段 需要枚举值才可以展示 还有最后的操作按钮

展示一下效果
分页也是可选的 不需要可以不传入插槽就行了
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
按钮点击的弹框 事件参数都是可以获取当前表格的值

// 插槽会返回当前插名称 根据插槽名称自定义样式 当前数据 data 如果没有传prop 返回即为空;
当前行数据rowData 和 当前行索引index
//<slot  :name="slotName" :data="prop ? row[prop] : null" :prop="item.prop" :rowData ="row" :index="$index"></slot>
//比如编辑按钮 我们只需要拿到行数据和索引就可以操作你的数据了
 <template v-slot:operate="{rowData, index}">
          <el-button @click="openEC2Dialog(rowData)" size="mini" type="primary">编辑					</el-button>
 </template>

《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》

支持自定义表头功能

两种方法
一: 传递renderHeader方法
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
methods里添加方法

renderHeader(h, {  column }) { 
        switch (column.property) { 
          case 'functionDescription':
            return [h('span', { }, [column.label+'这是自定义']), h('el-tooltip', {  props: {  placement: 'top', effect: 'light' } }, [h('div', {  slot: 'content' }, [h('p', { }, ['一个提示'])]), h('i', {  class: 'helpTips el-icon-info' ,style: 'cursor:pointer;'})])]
          default:
            return [h('span', { }, [column.label])]
        }
      },

然后查看效果
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
二:通过插槽
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
这里的是slotName+’Header’的方式 只要定义了slotName然后就可以设置了
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
我这里改动的是操作的显示 查看一下效果
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
这两种方法都可以改变表头 但是不要一起使用 一起使用会被第一个方法覆盖 插槽就不生效了~

详情内容展示

CommTable组件传入 showExpand true
然后在
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》
自定义内容就行了

<CommTable
        :tableData="tableData"
        :maxHeight="350"
        :tablecolumn="tablecolumn"
        :showExpand="true"
        :loading="tableLoading"
        :smallRow="true"
        >
        <template v-slot:expand="{data}">
          <span>详情内容{ { data}}</span>
        </template>
        <template v-slot:postContent="{data, index}">
          <div style="max-height: 46px;cursor: pointer;" v-clamp v-html="JSON.parse(data).content"></div>
        </template>
        <template v-slot:operate="{rowData, index}">
          <el-button @click="openTimeSelDialog(rowData)" size="mini" type="primary">置顶</el-button>
        </template>
    </CommTable>

效果图
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》

可拖动表格支持

//表格组件使用插件 sortablejs 自行npm下载依赖
import Sortable from "sortablejs";

使用案例

//template
//需要传入的字段: 
// dragTableFlag: 是否可以拖动 默认false 为true的时候需要传入下面的字段
//rowKey:能唯一确定行的key 
//tabClass: 这个需要给定一个值 如果是多个表格都需要拖动要唯一 
//@getDragTableSort: 为拖动后的回调 返回内容为当前表格数据
<CommTable
        :tableData="tableData"
        :maxHeight="350"
        :tablecolumn="tablecolumn"
        :loading="tableLoading"
        :dragTableFlag="true"
        @getDragTableSort="getDragTableSort"
        rowKey="id"
        :tabClass='`detailClass${rowId}`'
        :smallRow="true"
        >
   </CommTable>
 
 //methods
 getDragTableSort(data){ 
	console.log(data);//为表格当前排序的值 可以在这里作相应的取值操作或请求
 }

表格复选框选择 及其定位功能

checkbox 回调函数selectionChange
:selectionObj=“{show: true, fixed: true}” 是否显示行复选框 是否定位

 <CommTable
        :tableData="tableData"
        :tablecolumn="tablecolumn"
        :selectionObj="{show: true, fixed: true}"
        ref="tableRef"
        @selectionChange="selectionChange"
        :loading="loading"
        >
 </CommTable>  

效果查看
《vue element-ui el-table表格二次封装 自定义el-table表格组件 vue封装表格组件》

    原文作者:爱前端不爱恋爱
    原文地址: https://blog.csdn.net/qq_33477377/article/details/121860177
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞