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萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章