Vue开发element-ui公共table组件可显隐列和拖拽列

效果图:

话不多说,直接撸代码

<template>
  <div class="pub-table-cla">
    <el-button-group style="width: 100%;margin-bottom: 10px;">
      <div style="width: 50%;float: left;">
        <slot name="btnsArea"></slot>
      </div>
      <div style="float: right;height: 30px">
        <el-dropdown :hide-on-click='false' style="float: left; margin-right: 10px;margin-bottom: 13px;">
          <el-button type="default"class="pub-button-he">
            显示隐藏列 <span v-show="hiddenColumnTotal > 0">({{ hiddenColumnTotal }})</span><i
            class="el-icon-arrow-down el-icon--right"></i>
          </el-button>
          <el-dropdown-menu slot="dropdown" style="overflow-y: auto;max-height: 70%">
            <el-dropdown-item v-for="head in headers" :key="head.attr.prop">
              <el-switch v-model="head.isShow" :active-text="head.attr.label" @change="headerChange"></el-switch>
              <span></span>
            </el-dropdown-item>
          </el-dropdown-menu>
        </el-dropdown>
        <div style="float: right;">
          <slot name="searchBtn"></slot>
        </div>
      </div>
    </el-button-group>
    <div class="table-height">
      <div class="table-wrap w-table"  :class="{'w-table_moving': dragState.dragging}">
        <el-table
          ref="AppTable"
          :data="tabDatas"
          :stripe="true"
          border
          height="500"
          row-key="roleId"
          highlight-current-row
          @selection-change='handleSelectionChange'
          style="width: 100%;"
          :header-cell-class-name="headerCellClassName"
        >
          <!-- 多选列 -->
          <el-table-column type="selection" width="55" v-if="multable"></el-table-column>
          <el-table-column type="index" label="序号" v-if="isShowIndex" width="55"></el-table-column>
          <template v-for="(item,index) in dragHeaders">
            <el-table-column
              v-if="item.isShow && item.slot"
              :key="index"
              v-bind="item.attr"
              :show-overflow-tooltip="true"
              :column-key="index.toString()"
              :render-header="renderHeader"
            >
              <!--某一列插槽-->
              <template slot-scope="scope">
                <slot :name="item.attr.prop" :row='scope.row'></slot>
              </template>
            </el-table-column>
            <el-table-column
              v-else-if="item.isShow"
              :key="index"
              v-bind="item.attr"
              :show-overflow-tooltip="true"
              :column-key="index.toString()"
              :render-header="renderHeader"
            >
            </el-table-column>
          </template>

          <!-- 操作列 -->
          <template v-if="isShowOperate">
            <el-table-column
              v-if="operationNum == 3"
              label="操作"
              width="160"  >
              <template slot-scope="scope">
                <!-- 将作用域插槽返回的对象scope继续通过作用域插槽暴露出去 -->
                <slot :row='scope.row'></slot>
              </template>
            </el-table-column>
            <el-table-column
              v-else
              label="操作"
              width="100"  >
              <template slot-scope="scope">
                <!-- 将作用域插槽返回的对象scope继续通过作用域插槽暴露出去 -->
                <slot :row='scope.row'></slot>
              </template>
            </el-table-column>
          </template>
        </el-table>
      </div>
    </div>
  </div>
</template>

<script>

  export default {
    name: 'pub-table',
    props: {
      //表头参数
      tabColumns: {
        type: Array,
        required: true,
        validator: (cols) => {
          return cols.length >= 1 //表格至少需要1列
        }
      },
      //展示的列数据
      tabDatas: Array,
      //是否多选
      multable: {
        type: Boolean,
        default: true
      },
      //几种操作用于设置操作列宽度
      operationNum: {
        type: Number,
        default: 2
      },
      //是否显示操作
      isShowOperate:{
        type: Boolean,
        default: true
      },
      //是否显示序号
      isShowIndex:{
        type: Boolean,
        default: true
      },
    },
    computed: {
      //隐藏列数
      hiddenColumnTotal () {
        return this.headers.filter(h => !h.isShow).length
      },
    },
    created () {
      this.headers = this.tabColumns.map((c) => {
        if (c.isShow === undefined) {
          this.$set(c, 'isShow', true)
        }
        return c
      })
      this.dragHeaders = this.headers;
    },
    data () {
      return {
        headers: [],
        dragHeaders:[],
        dragState: {
          start: -1, // 起始元素的 index
          end: -1, // 结束元素的 index
          move: -1, // 移动鼠标时所覆盖的元素 index
          dragging: false, // 是否正在拖动
          direction: undefined // 拖动方向
        }
      }
    },
    mounted () {
    },
    watch: {
    },
    methods: {
      headerChange(){
        this.dragHeaders = []
        for(let i=0;i<this.headers.length;i++){
          if(this.headers[i].isShow){
            this.dragHeaders.push(this.headers[i])
          }

        }
      },
      headerCellClassName ({column, columnIndex}) {
        if(this.multable == true && this.isShowIndex == true){
          return (columnIndex - 2 === this.dragState.move ? `darg_active_${this.dragState.direction}` : '')
        }else if (this.multable == true || this.isShowIndex == true) {
          return (columnIndex - 1 === this.dragState.move ? `darg_active_${this.dragState.direction}` : '')
        }else{
          return (columnIndex === this.dragState.move ? `darg_active_${this.dragState.direction}` : '')
        }

      },
      renderHeader (createElement, {column}) {
        return createElement(
          'div', {
            'class': ['thead-cell'],
            on: {
              mousedown: ($event) => {
                this.handleMouseDown($event, column)
              },
              mouseup: ($event) => {
                this.handleMouseUp($event, column)
              },
              mousemove: ($event) => {
                this.handleMouseMove($event, column)
              }
            }
          }, [
            // 添加 <a> 用于显示表头 label
            createElement('a', column.label),
            // 添加一个空标签用于显示拖动动画
            createElement('span', {
              'class': ['virtual']
            })
          ])
      },
      // 按下鼠标开始拖动
      handleMouseDown (e, column) {
        this.dragState.dragging = true
        this.dragState.start = parseInt(column.columnKey)
        // 给拖动时的虚拟容器添加宽高
        let table = document.getElementsByClassName('w-table')[0]
        let virtual = document.getElementsByClassName('virtual')
        for (let item of virtual) {
          item.style.height = table.clientHeight - 1 + 'px'
          item.style.width = item.parentElement.parentElement.clientWidth + 'px'
        }
      },

// 鼠标放开结束拖动
      handleMouseUp (e, column) {
        this.dragState.end = parseInt(column.columnKey) // 记录起始列
        this.dragColumn(this.dragState)
        // 初始化拖动状态
        this.dragState = {
          start: -1,
          end: -1,
          move: -1,
          dragging: false,
          direction: undefined
        }
      },

// 拖动中
      handleMouseMove (e, column) {
        if (this.dragState.dragging) {
          let index = parseInt(column.columnKey) // 记录起始列
          if (index - this.dragState.start !== 0) {
            this.dragState.direction = index - this.dragState.start < 0 ? 'left' : 'right' // 判断拖动方向
            this.dragState.move = parseInt(column.columnKey)
          } else {
            this.dragState.direction = undefined
          }
        } else {
          return false
        }
      },

// 拖动易位
      dragColumn ({start, end, direction}) {
        if (start < 0 || end < 0 || start == end) {
          return
        }
        let tempData = []
        let left = direction === 'left'
        let min = left ? end : start - 1
        let max = left ? start + 1 : end
        for (let i = 0; i < this.dragHeaders.length; i++) {
          if (i === end) {
            tempData.push(this.dragHeaders[start])
          } else if (i > min && i < max) {
            tempData.push(this.dragHeaders[left ? i - 1 : i + 1])
          } else {
            tempData.push(this.dragHeaders[i])
          }
        }
        this.dragHeaders = tempData
      },
      //选择项改变时候(返回当前选中的行)
      handleSelectionChange (selection) {
        this.$emit('rowSelectionChanged', selection)
      },
    }
  }
</script>

<style lang="less" scoped>
  .btns-area {
    padding-left: 0px;
    text-align: left;
  }
  .table-height{
    height:  calc(~'100% - 60px')
  }
  .pub-table-cla{
    height:  calc(~'100% - 42px')
  }
  .pub-button-he{
    height: 30px !important;
  }
</style>

样式设定:在base.less中添加

.w-table {
  .el-table th {
    padding: 0;
    .virtual {
      position: absolute;
      left: 10px;
      display: block;
      width: 0;
      height: 0;
      margin-left: -10px;
      z-index: 99999999;
      background: none;
      border: none;
    }
    &.darg_active_left {
      .virtual {
        border-left: 2px solid  #309fff;
      }
    }
    &.darg_active_right {
      .virtual {
        border-right: 2px solid  #309fff;
      }
    }
  }
  .thead-cell {
    padding: 0;
    display: inline-flex;
    flex-direction: column;
    align-items: left;
    cursor: move;
    overflow: initial;
    &:before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
    }
  }
  &.w-table_moving {
    .el-table th .cell {
      cursor: move !important;
    }
    .el-table__fixed {
      cursor: not-allowed;
    }
  }
}

父组件调用:

引入:

import PubDialog from '@/components/common/pub-dialog'
 components: {
      PubDialog:PubDialog
    },

使用:

 <pub-table
          :tab-columns='tabColumns'
          :tab-datas='tabDatas'
          :operationNum= '3'
          @rowSelectionChanged='rowSelected'
          :isShowOperate='isShowOperate'
          :multable='multable'
          :isShowIndex='isShowIndex'
        >

          <template slot="btnsArea">
              <el-button type="primary"  class="addGreenBtn"  icon="el-icon-plus">添加</el-button>
              <el-button type="primary"  class="greenBtn"icon="el-icon-delete">删除</el-button>
           

          </template>

          <template slot="searchBtn">
            <input class="role-search-input" type="text" v-model="searchKw" placeholder="输入关键字搜索">
            <span class="icon iconfont icon-search" v-on:click="searchRole"></span>
          </template>
          <template slot='name' slot-scope="scope">
           测试{{scope.row.name}}
          </template>
          <template slot-scope="scope">
            <el-button  @click="editRole(scope.row)" class="el-table-btn" type="text">编辑</el-button>
            <el-button @click="readRole(scope.row)" class="el-table-btn" type="text">查看</el-button>
            <el-button @click="relation(scope.row)" class="el-table-btn" type="text">相关用户</el-button>
          </template>
        </pub-table>

父组件参数说明:

tabColumns:列头,部分参考(attr标识你这列得属性和参数,isShow表示默认是否显示此列,solt表示此类是否使用插槽操作此类,参考上面代码name列特殊操作,):
 tabColumns: [
          {
            attr: {prop: 'code', label: '编码',sortable: true}
          },
          {
            attr: {prop: 'name', label: '名称'},
            isShow: true,
            slot: true,
          },
]

 

isShowOperate:true,  是否显示操作列
multable:true,是否显示多选列
isShowIndex:true,是否显示序号列

table列上得操作(添加删除)都是通过插槽,仅供参考,

选中行后父组件操作:

 //监听选中的行
      rowSelected(rows) {
        this.checkedRows = rows;
        console.log(this.checkedRows);
      }

参考:

思否问答

gitee源码

发布了68 篇原创文章 · 获赞 7 · 访问量 3万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章