前言:

再通过使用element-ui和iview这两种框架的table时的对比发现,iview比ele有个优点就是,他中间支持render渲染,但是iview的事件又是明显少于ele的,比如我们需要右键的事件,或者点击表头的事件,在iview是得不到解决的,所以在这里我对element的table进一步封装,使得他可以更好的满足我们的需要:

首先我在这里是需要引入两个组件的:(先代码,再谈谈怎么实现的)

第一个组件:iTableT.vue,这里面主要是对得到的数据进行处理,并实现功能的底层功能组件

<!--region 封装的分页 table-->
<template>
 <div class="table">
    <el-table id="iTable" :class="tableClass"
      v-loading.iTable="options.loading"
      :data="list"
      :stripe="options.stripe"
      :border="options.border"
      :highlight-current-row="options.highlightCurrentRow"
      :lazy="options.lazy"
      :load='loadGetData'
      ref="mutipleTable"
      style='width:100%;'
      @row-click='clickRow' @row-dblclick='dblclickRow' @row-contextmenu='contextmenu' @header-click='headClick' @header-contextmenu='headcontextmenu'
      @current-change='rowChange'
      @selection-change="handleSelectionChange">

      <!--region 选择框-->
      <el-table-column v-if="options.mutiSelect" type="selection" style="width: 55px;">
      </el-table-column>
      <!--endregion-->

      <!--region 数据列-->
      <template v-for="(column, index) in columns">

        <!-- slot 添加自定义配置项 -->
        <slot  v-if="column.slot"  :name="column.slot"></slot>

         <!--排序-->
        <el-table-column v-else-if="column.type=='index'" type="index" :width="column.width" :label="column.label"></el-table-column>




        <!-- 默认渲染列 -->
        <el-table-column v-else :prop="column.prop"
            :key='column.label'
            :label="column.label"
            :align="column.align"
            :width="column.width"
            :show-overflow-tooltip="true">
            <template slot-scope="scope">
                <template v-if="!column.render">
                  <template v-if="column.formatter">
                  <span v-html="column.formatter(scope.row, column)"></span>
                  </template>
                  <template v-else>
                  <span>{{scope.row[column.prop]}}</span>
                  </template>
                </template>
                <template v-else>
                  <expand-dom :column="column" :row="scope.row" :render="column.render" :index="index"></expand-dom>
                </template>
            </template>
        </el-table-column>

      </template>
      <!--endregion-->

    </el-table>

 </div>
</template>
<!--endregion-->
<script>
 export default {
    props: {
        list: {
          type: Array,
          default: []
          }, // 数据列表
        columns: {
          type: Array,
          default: []
          }, // 需要展示的列 === prop:列数据对应的属性,label:列名,align:对齐方式,width:列宽
        options: {
          type: Object,
          default: {
            height:300,//默认高度-为了表头固定
            stripe: false, // 是否为斑马纹 table
            highlightCurrentRow: false, // 是否要高亮当前行
            border:false,//是否有纵向边框
            lazy:false,//是否需要懒加载
          },
        }, // table 表格的控制参数
        tableClass:{
          type: String,
          default: 'hxTable'
        },
    },
    //组件
    components: {
      expandDom: {
        functional: true,
        props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
          type: Object,
          default: null
          }
          },
        render: (h, ctx) => {
          const params = {
          row: ctx.props.row,
          index: ctx.props.index
          }
        if (ctx.props.column) params.column = ctx.props.column
          return ctx.props.render(h, params)
        }
      }
    },
    // 数据
    data () {
      return {
        pageIndex: 1,
        multipleSelection: [], // 多行选中
      }
    },
    mounted () {
    },
    computed: {
    },
    methods: {
         loadGetData(row,treeNode,resolve){//懒加载事件数据

        },
        handleSelectionChange (val) {// 多行选中
          this.multipleSelection = val
          this.$emit('handleSelectionChange', val)
        },
        clickRow(row, column, event){//单击行事件
          let data = {
            'row':row,
            'column':column,
            'event':event,
          }
          this.$emit('clickRow',data);
        },
        dblclickRow(row, column, event){//双击行事件
          let data = {
            'row':row,
            'column':column,
            'event':event,
          }
          this.$emit('dblclickRow',data);
        },
        contextmenu(row, column, event){//右键行事件-没去掉页面默认的
          let data = {
            'row':row,
            'column':column,
            'event':event,
          }
          this.$emit('contextmenu',data);
        },
        headClick(column, event){//头部列点击事件
          let data = {
            'column':column,
            'event':event,
          }
          this.$emit('headClick',data);
        },
        headcontextmenu(column, event){//头部列右键点击事件
           let data = {
            'column':column,
            'event':event,
          }
          this.$emit('headcontextmenu',data);
        },
        rowChange(currentRow, oldCurrentRow){//当前行发生改变时的事件
           let data = {
            'currentRow':currentRow,
            'oldCurrentRow':oldCurrentRow,
          }
          this.$emit('rowChange',data);
        },

    }
  }
</script>
<style lang="less" >

</style>

第二:第二个组件是我的slot组件,这里是专门提出来了,来实现我们更多的需要:

<template>
    <div class="tableSlot" style="">
        <CommonTable
          :columns="columns"  :list="list"  :options='optionsData'
          @clickRow='clickRow' @dblclickRow='dblclickRow' @contextmenu='contextmenu' @headClick='headClick' @headcontextmenu='headcontextmenu'
          @rowChange='rowChange'  @handleSelectionChange='handleSelectionChange'
          >
            <!-- 内容slot -->
            <el-table-column slot="operate" label="操作">
              <template slot-scope="scope">
                <el-button type="text" size="small" @click="edit(scope.row)">编辑</el-button>
                <el-button type="text" size="small" @click="deleteUser(scope.row)">删除</el-button>
              </template>
            </el-table-column>
            <el-table-column slot="twomenu" label="二级图层">
              <template slot-scope="scope">
                <span class="demonstration">{{ scope.row.twomenu }}</span>
                <el-cascader
                  v-model="value"
                  :options="options"
                  :props="{ expandTrigger: 'hover' }"
                  @change="handleChange"
                  :show-all-levels="false">
                </el-cascader>
              </template>
          </el-table-column>
      <!--排序-->
      <el-table-column slot="index" label="排序">
        <template slot-scope="scope">
        <span>{{(paging.pageNum - 1) * paging.pageSize + scope.$index + 1}}</span>
        </template>
      </el-table-column>

           <!-- 头部slot -->
          <el-table-column width=150 prop="zt" slot="name">
              <template slot-scope="scope" slot="header">
                  <el-popover
                  title="标题"
                  width="200"
                  trigger="click"
                  content="这是一段内容,这是一段内容,这是一段内容,这是一段内容。">
                  <span slot="reference">姓名</span>
                  </el-popover>
              </template>
          </el-table-column>
      </CommonTable>
    </div>
</template>

<script>
  import CommonTable from '@/components/tableEle/iTableT'//table
  // import CommonTable from '@/components/tableEle/iTable'//table
  export default {
    name:'slot统一管理',
     props:{
      columns:Array,
      list:Array,
      options:Object,
    //将当前页和一页显示多少条作为参数传进来保证序号的准确性
      paging: {
        type:Object,
        default: () => {
          return {
            pageNum: 1,
            pageSize: 10,
          }
        }
      }
    },
    data () {
      return {
            optionsData:{
                stripe: false, // 是否为斑马纹 table
                loading: false, // 是否添加表格loading加载动画
                highlightCurrentRow: true, // 是否支持当前行高亮显示
                mutiSelect: false, // 多选框
                height:400,//table高度-设置才能固定表头
            }, // table 的参数
      };
    },

    components: {
      CommonTable
    },
     created(){
      document.oncontextmenu = function(){return false};//去掉右键点击默认菜单
      if( this.options != undefined){
        this.optionsData = this.options;
      }
     },
    methods: {
      handleSelectionChange(data){//选择项发生改变,勾选框
         this.$emit('handleSelectionChange', data)
      },
      clickRow(data){//点击行事件
        this.$emit('clickRow', data)
      },
      dblclickRow(data){//双击行事件
        this.$emit('dblclickRow', data)
      },
      contextmenu(data){//右键点击事件
        this.$emit('contextmenu', data)
      },
      headClick(data){//头部列点击事件
        this.$emit('headClick', data)
      },
      headcontextmenu(data){//头部列右键点击事件
        this.$emit('headcontextmenu', data)
      },
      rowChange(data){//当前行发生改变
        this.$emit('rowChange', data)
      },
    },

  }

</script>
<style lang='less' scoped>

</style>

第三是调动部分的代码:

<cTable 
:columns="GJcolumns" 
:list="TqycgjxxData" 
 tableClass="jrzytjTb"

  :paging="searchForm"  加上这个以后就可用slot:'index',方法源码在cTable.vue里面

></cTable>
//注意这里封装了一个class,可以设置每个table的class,目的用来更改他的高度,实现头部固定,上下滚动条的效果


data里面的数据:

//查询参数
searchForm:{
          name:'',
          type:'',
          pageNum:1,//当前页
          pageSize:10,//一页显示多少条
        },



GJcolumns:{
        {
            label:'序号',
            slot:'index',  //使用这个的话,必须传入paging这个参数(自用)
            //type:'index',  如果使用这个是element默认的序号
            width:55
        },
        {
            label: 'id',
            prop: 'id',
            align: 'center',
            width: 1,
          },
          {
            label: '线路',
            prop: 'ssxl',
            align: 'center',
            width: 126,
          },
          {
            label: '台区',
            prop: 'tqmc',
            align: 'center',
            width: 126,
          },
          {
            slot:'select',//注意这里是引用slot
            align: 'center',
            width: 126,
          },
          {
            label: '异常描述',
            prop: 'ycms',
            align: 'center',
            width: 126,
          },
          {
            label: '发生时间',
            prop: 'fssj',
            align: 'center',
            width: 170,
          },
           {
            label: '等级',
            prop: 'qxdj',
            align: 'center',
            width: 110,
            render: (h, params) => {
              let dj = params.row.qxdj;
              let style={};
              if(dj == '一般'){
                style.color = '#00fffc';
              }else if(dj == '重大'){
                style.color = '#ff5816';
              }else if(dj == '紧急'){
                style.color = '#ffc000';
              }
              return h('div', {
                style:style
              } ,params.row.qxdj)
            }
         },
       ],
}

好了,组件都发过去了,再来谈谈这一套的实现原理,优点,和不足之处吧:

优点:1、可以完美的将iview的render那种模式应用在element-ui的table 中

           2、可以使用头部slot来更换头部的内容和元素,比如写一个下拉的组件,然后放进去是可以的,写一个popover的弹框也            是可以的

           3、也有内容slot,放进去可以写入操作这类型的特殊组件

不足之处:因为,我这里是将slot单独都拿出来封装(业务需要),没办法实现slot的再次封装,在slot里面必须写死他的prop                      值,不然拿不到数据;还有,注意不要在内部设置element自带的高度,经过测试当数据量特别大,页面会卡死,

这个组件的封装就到这里:

使用步骤:

1、

elementui 人员选择 element ui table render_数据

2、

elementui 人员选择 element ui table render_elementui 人员选择_02

3、

elementui 人员选择 element ui table render_右键_03

4、

elementui 人员选择 element ui table render_点击事件_04

5、

elementui 人员选择 element ui table render_数据_05