基於element ui 二次封裝表格組件,行,列都可配置拖拽、多選框勾選翻頁記憶

<template>
  <div class="jzl-table">
    <el-table
      :data="tableData"
      :ref="tableRef"
      @select="select"
      @select-all="selectAll"
      @selection-change="selectionChange"
      :height="filterParams(tableConfig.height,null)"
      :max-height="filterParams(tableConfig.maxHeight,null)"
      :stripe="filterParams(tableConfig.stripe,false)"
      :empty-text="filterParams(tableConfig.emptyText,'暫無數據')"
      :border="tableConfig.border||true"
      :rowClassName="tableConfig.rowClassName || null"
      :showSummary="tableConfig.showSummary || false"
      :summaryMethod="tableConfig.summaryMethod?summaryMethod : null "
      :sumText="tableConfig.sumText || '合計'"
      :row-key="tableConfig.rowKey||null"
      v-if="!hideTable"
      class="jzl-table"
    >
      <template v-for="(item,index) in columnConfig">
        <el-table-column
          v-if="defaultColumnType.includes(item.type) && !item.hide"
          :type="item.type"
          :key="index"
          :fixed="item.fixed||false"
          :align="item.align||align"
          :width="item.width||55"
          :minWidth="item.minWidth|| 'auto'"
          :label="item.label"
          :reserve-selection="item.reserveSelection||false"
        ></el-table-column>

        <el-table-column
          v-else-if="item.type === 'switch' && !item.hide"
          :fixed="item.fixed||false"
          :width="item.width||''"
          :minWidth="item.minWidth|| 'auto'"
          :key="index"
          :align="item.align||align"
          :label="item.label"
          :prop="item.prop"
        >
          <template slot-scope="{row,$index}">
            <el-switch
              class="switchBtn"
              v-model="row[item.prop]"
              :active-color="item.switchConfig.activeColor||'#13ce66'"
              @change="item.switchCallBack?item.switchCallBack($event,row[item.prop],$index,row):new Function()"
              :active-value="item.switchConfig.activeValue||1"
              :inactive-value="item.switchConfig.inactiveValue||0"
              :inactive-color="item.switchConfig.inactiveColor||'#cccccc'"
              :disabled="item.switchConfig.permission||false"
            ></el-switch>
          </template>
        </el-table-column>

        <el-table-column
          v-else-if="item.type === 'button' && !item.hide"
          :fixed="item.fixed||false"
          :align="item.align||align"
          :width="item.width||''"
          :minWidth="item.minWidth|| 'auto'"
          :key="index"
          :label="item.label"
          :prop="item.prop"
        >
          <template slot-scope="{row,$index}">
            <div>
              <template v-for="(btn,i) in item.buttonConfigArray">
                <el-switch
                  :key="i"
                  class="switchBtn"
                  v-if="buttonType(btn.type) === 'switch' && !btnHide(btn.hide,row)"
                  v-model="btn.model"
                  :active-color="btn.switchConfig.activeColor||'#13ce66'"
                  @change="btn.switchCallBack?btn.switchCallBack($event,btn.prop,$index,row):new Function()"
                  :active-value="btn.switchConfig.activeValue||1"
                  :inactive-value="btn.switchConfig.inactiveValue||0"
                  :inactive-color="btn.switchConfig.inactiveColor||'#cccccc'"
                  :disabled="btn.permission||false"
                ></el-switch>
                <slot
                  v-else-if="buttonType(btn.type)==='slot'  &&  !btnHide(btn.hide,row)"
                  :name="btn.soltName"
                  :data="{row,$index}"
                  @click="btn.click?btn.click(row,$index):new Function()"
                ></slot>

                <el-button
                   v-else-if="! btnHide(btn.hide,row)"
                  @click="btn.click?btn.click(row,$index):new Function()"
                  :key="i"
                  :class="btn.class"
                  :icon="btn.icon||''"
                  :type="buttonType(btn.type)"
                  :disabled="btn.permission || false"
                >{{btn.name}}</el-button>
              </template>
            </div>
          </template>
        </el-table-column>
        <slot
          v-else-if="item.type==='solt' && !item.hide"
          :name="item.soltName"
          :prop="item.prop"
          :label="item.label"
          :width="item.label"
        ></slot>

        <el-table-column
          v-else-if="!item.hide"
          :key="index"
          :fixed="item.fixed||false"
          :align="item.align||align"
          :width="item.width||''"
          :minWidth="item.minWidth|| 'auto'"
          :label="item.label"
          :prop="item.prop"
          :show-overflow-tooltip="item.overflowHide||true"
        >
          <template slot-scope="{row,$index}">
            <div
              :class="`${item.clickFn?'alink':''} ${item.className} ${item.classNameFunc?item.classNameFunc(row,row[item.prop],$index):''} ${item.overflowHide===false?'':'overflowHide'}`"
              @click="item.clickFn?item.clickFn(row,row[item.prop],$index,item.prop):()=>{}"
            >{{ item.formatter?filterColText(row,row[item.prop],$index,item.formatter):row[item.prop]}}</div>
          </template>
        </el-table-column>
      </template>
    </el-table>
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="this.pageConfig.page"
      :page-sizes="pageConfig.sizes||[20,50,100,200]"
      :page-size="pageSize"
      layout="total, sizes, prev, pager, next, jumper"
      :total="pageConfig.total||0"
      v-if="!hidePage"
    ></el-pagination>
  </div>
</template>
 
<script>
import draggable from 'vuedraggable'
import Sortable from 'sortablejs'

export default {
  components: {
    draggable,
    Sortable
  },
  props: {
    /**
     * ref 標識
     * 用於用戶獲取表格
     * 調用element的Table Methods裏面的方法
     * 
     */
    tableRef: {
      type: String,
      default: 'jzl_table'
    },
    // 表格數據
    tableData: {
      type: Array,
      default: () => {
        return []
      }
    },

    /** 
     * 表格配置
     * 
     * 目前支持的函數key有
     * select(當用戶手動勾選數據行的 Checkbox 時觸發的事件) 
     * selectAll(當用戶手動勾選全選 Checkbox 時觸發的事件)
     * selectionChange(當選擇項發生變化時會觸發該事件)
     * 常用配置有
     * height:string/number	表格高
     * maxHeight:string/number 	表格最大高度
     * stripe:boolean 是否爲斑馬紋
     * emptyText:string 空數據時的文本
     * border:boolean
     * showSummary:boolean是否顯示合計
     * summaryMethod:function ({ columns, data } 自定義的合計計算方法
     * sumText:String 合計行第一列的文本   
     * rowClassName:function({row, rowIndex}) /String 行的  className 的回調方法,
     * 也可以使用字符串爲所有行設置一個固定的 className,通常用於控制某行的顏色
     * rowKey:Function(row)/String行數據的 Key,用來優化 Table 的渲染;
     * 在使用 reserve-selection 功能與顯示樹形數據時,
     * 該屬性是必填的。類型爲 String 時,
     * 支持多層訪問:user.info.id,但不支持 user.info[0].id,此種情況請使用 Function
     * 
     * */
    tableConfig: {
      type: Object,
      default: () => {
        return {}
      }
    },
    /**
     * 表格列配置
     * {
     * label:string, // 列標題
     * prop:string, // 對應列的字段名
     * type:string, // 當前列類型支持solt(插槽,自定義)、selection(多選框)、index(索引)、switch(switch開關)、button(按鈕欄)、text(div,普通列,默認值))
     * reserveSelection:boolean, // 它僅對 type=selection 的列有效,類型爲 Boolean,爲 true時會在數據更新之後記住之前選擇的數據。(需要指定row-key)    
    * switchCallBack:Function, // 當type爲switch時必傳
     * buttonConfigArray:array, // 當type爲button時必傳
     * width:string, // 對應列的寬度
     * minWidth:string, // 最小列寬
     * clickFn:function, //當前列點擊回調,常用於點跳轉Function(row, cellValue,$index,prop( 對應列的字段名)) 
     * fixed:string, boolean // 列是否固定在左側或者右側,true 表示固定在左側
     * formatter:Function,string,array // 回調函數參數Function(row, cellValue, index) ,
     * string代表是掛載在全局的過濾函數 ,array代表val是下標array[val]
     * align:string // 對齊方式
     * className:string // 列的樣式類名,用於改變類顏色
     * classNameFunc:function // 用於動態計算列類名函數,便於根據不用內容顯示不同樣式,Function(row, cellValue, index){return calss}
     *overflowHide:boolean  //是否超出隱藏,默認是
      hide:boolean: true 代表隱藏此列
     * }
     * 
     */
    columnConfig: {
      type: Array,
      required: true,
      default: () => []
    },
    /**
     * 分頁配置
     * page:number, // 初始頁數,默認1
     * pageSize:number , // 初始條數 。默認20
     * pageChange:Function // 點擊分頁頁數或者條數改變回調函數 Function(page.pageSize)
     * sizes:array //下拉選擇頁數數組  默認[20,50,100,200]
     * total:總數
    */
    pageConfig: {
      type: Object,
      default: () => {
        return {
          page: 1,
          pageSize: 20
        }
      }
    },
    /**
     * 隱藏表格,單獨顯示分頁
     * 
     */
    hideTable: {
      type: Boolean,
      default: false
    },
    /**
     * 隱藏分頁,單獨顯示錶格
     * 
     */
    hidePage: {
      type: Boolean,
      default: false
    },
    /**
     * 默認表格對齊方式
     * */
    align: {
      type: String,
      default: 'left'
    },
   
    // 是否開啓拖拽
    drag: {
      type: Boolean,
      default: false
    },
    // 拖拽結束回調函數
    dragOnEnd: {
      type: Function,
      default: new Function()
    }

  },
  data () {
    return {
      defaultFunction: new Function(),
      defaultColumnType: ['index', 'selection'],
      page: 1,
      pageSize: 20
    }
  },
  mounted () {
    this.pageConfig.page = this.pageConfig.page || 1
    this.pageSize = this.pageConfig.pageSize || 20
    if (this.drag) {
      if (!this.tableConfig.rowKey) {
        console.warn('已開啓拖拽功能,請定義rowKey,rowKey爲行數據的 Key,用來優化 Table 的渲染;在使用 拖拽功能時,該屬性是必填的。類型爲 String 時,支持多層訪問:user.info.id,但不支持 user.info[0].id,此種情況請使用 Function。')
      }
      this.openDrag()
    }
  },
  methods: {
    // 行拖拽
    openDrag () {
      const tbody = document.querySelector('.el-table__body-wrapper tbody')
      const _this = this
      Sortable.create(tbody, {
        onEnd (data) {
          _this.dragOnEnd(data)
          // const currRow = _this.tableData.splice(oldIndex, 1)
          // 在新位置插入新值
          // _this.tableData.splice(newIndex, 0, currRow[0])
        }
      })
    },
    summaryMethod (params) {
      if (this.tableConfig.summaryMethod) {

        // 如果有高,表頭固定需要在初始化時主動觸發重新計算合計行位置
        if (this.tableConfig.height) {
          this.$nextTick(() => {
            this.$refs.jzl_table.doLayout()
          })
        }

        return this.tableConfig.summaryMethod(params)
      }

    },
    buttonType (type) {
      return type || 'primary'
    },
    handleCurrentChange (page) {
      this.pageConfig.page = page
      this.pageConfig.pageChange(page, this.pageSize)
    },
    // 改變每頁數量時,當前頁回到第一頁,防止請求不到數據
    handleSizeChange (pageSize) {
      this.pageSize = pageSize
      this.pageConfig.page = 1
      this.pageConfig.pageChange(this.pageConfig.page, pageSize)
    },
    //  過濾參數
    filterParams (params, defaultVal) {
      return params || defaultVal
    },
    filterColText (row, val, index, filterFn) {
      try {
        if (typeof filterFn === 'function') {
          return filterFn(row, val, index)
        } else if (typeof filterFn === 'string') {
           
          if (this.__proto__.constructor.filter(filterFn)) {
            return this.__proto__.constructor.filter(filterFn)(val)
          } else {
            console.warn('無法找到掛載在全局的過濾函數=== ' + filterFn + ' ====')
            return val
          }
        } else if (Array.isArray(filterFn)) {
          return filterFn[val]
        }
      } catch (e) {
        console.error('表格過濾函數 == ' + filterFn + ' ==參數錯誤:' + e)
      }
    },
    // 操作欄按鈕隱藏
    btnHide(fn,row){
      if(fn === undefined)
      return false
      try {
         if (typeof fn === 'function') {
            return fn(row)
         }else{
           console.error('buttonConfigArray配置項中的hide必須爲函數類型,現在獲取到的類型爲:'+typeof fn)
         }
      } catch (error) {
        console.log('操作按鈕隱藏函數:'+error)
      }
    },
    selectionChange (e) {
      if (this.tableConfig.selectionChange) {
        this.tableConfig.selectionChange(e)
      }
    },
    selectAll (e) {
      if (this.tableConfig.selectAll) {
        this.tableConfig.selectAll(e)
      }
    },
    select (selection, row) {
      if (this.tableConfig.select) {
        this.tableConfig.select(selection, row)
      }
    }

  }
}
</script>
 
<style lang="scss" scoped>
.jzl-table {
  width: 100%;
  margin: 10px auto;
}
.el-select .el-input .el-select__caret {
  line-height: 30px;
}
.delt.el-button--text {
  color: #ff0000;
}
//排序圖標
.el-icon-sort-down,
.el-icon-sort-up {
  transform: scale(1, 1.2);
  margin: 0;
  margin-right: -2px;
  padding: 0;
}
.el-icon-sort-down:before,
.el-icon-sort-up:before {
  color: #409eff;
  font-size: 16px;
  cursor: pointer;
}
.overflowHide {
  width: 100%;
  overflow: hidden; //超出的文本隱藏

  text-overflow: ellipsis; //溢出用省略號顯示

  white-space: nowrap; //溢出不換行
}
.alink {
  color: #0068d0;
}
.alink:hover {
  cursor: pointer;
  text-decoration: underline;
}
</style> 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章