基於element ui的el-table二次封裝


記錄下自己封裝table基礎crud方便開發

2021-04-21 支持key為‘companies[0].pivot.name’的特殊字符串

2021-04-25 優化特殊字符串判斷處理 參考大佬microanswer的寫法

2021-04-26 增加方法二eval()

2021-05-21 增加表單嵌套expand

2021-07-05 增加自定義頭部信息 (v-slot:xxx.header)

2021-08-24 使用v-bind="$attrs"及v-on=“$listeners”簡化代碼,修改使用文檔

 

待解決問題:

無法在封裝后的組件中用refs直接調用el-table自帶的方法,需要自己在methods中轉

 

效果圖

 

dw-crud的使用    columnChange組件

<template>
    <dw-crud selection :columns="columns" :data="data" @selection-change="handleSelectionChange">
        <!-- 當column中的slot為true 則以key為插槽名(#key)傳入 -->
        <template #depot="{ row }">
            <column-change type="select" :value="row.depot" :options="depotOption" @change="changeNum(row.id, $event)" />
        </template>
        <template #number="{ row }">
            <column-change type="input" search :value="row.number" @change="changeNum(row.id, $event)" />
        </template>
        <!-- #op特指操作列 可以自行去dw-crud修改 -->
        <template #op="{ row }">
            <el-button type="text">加入銷售訂單</el-button>
            <el-button type="text">刪除</el-button>
        </template>
    </dw-crud>
</template>

<script>
import dwCrud from './dwCrud'
// 個人封裝的行內編輯input和select
import columnChange from './columnChange'

export default {
    components: {
        dwCrud,
        columnChange,
    },
    data() {
        return {
            columns: [
                {
                    title: 'ID',
                    key: 'id',
                    width: '50px',
                },
                {
                    title: '倉庫',
                    slot: 'depot',
                },
                {
                    title: '數量',
                    slot: 'number',
                },
            ],
            //   測試數據
            depotOption: [
                { label: '倉庫A', value: 1 },
                { label: '倉庫B', value: 2 },
                { label: '倉庫C', value: 3 },
            ],
            data: [
                {
                    id: 1,
                    depot: 1,
                    number: 7000,
                },
                {
                    id: 2,
                    depot: 2,
                    number: 5000,
                },
            ],
        }
    },
    methods: {
        changeNum(id, val) {
            console.log('父組件取值:', id, val)
        },
        handleSelectionChange() {},
    },
}
</script>

<style></style>

 

 

 

dwCrud組件(el-table)

根據目前的業務需求封裝。用了slot具名插槽去區分特殊的行內展示<template>

<template>
    <el-table ref="table" v-bind="$attrs" v-on="$listeners" :size="size">
        <!-- 多選框 -->
        <el-table-column v-if="selection" type="selection" align="center" width="55" />
        <!-- 表單嵌套 -->
        <el-table-column v-if="expand" type="expand">
            <template slot-scope="{ row, $index }">
                <slot name="expand" :row="row" :index="$index"></slot>
            </template>
        </el-table-column>
        <!-- 文本數據渲染 -->
        <template v-for="(column, index) in columns">
            <el-table-column :key="index" :min-width="column.width" :sortable="column.sortable" :prop="column.key">
                <!-- 自定義頭部  slotName.header -->
                <template slot="header" slot-scope="{ row, $index }">
                    <slot v-if="$scopedSlots[`${column.slot}.header`]" :name="`${column.slot}.header`"></slot>
                    <span v-else>{{ column.title }}</span>
                </template>

                <!-- 主體內容 -->
                <template slot-scope="{ row, $index }">
                    <!-- 如果有插槽 -->
                    <slot v-if="column.slot" :name="column.slot" :row="row" :index="$index"></slot>
                    <!-- 過濾 (暫未完善) -->
                    <!-- <span v-else-if="column.format">{{ key2val(row, column.key) | column.format }}</span> -->
                    <!-- 默認 -->
                    <span v-else>{{ key2val(row, column.key) }}</span>
                </template>
            </el-table-column>
        </template>
        <!-- 特殊處理的操作布局 默認存在 -->
        <el-table-column :fixed="opFixed" label="操作" v-if="operation" :min-width="opWidth">
            <template slot-scope="{ row, $index }">
                <slot name="op" :row="row" :index="$index"></slot>
            </template>
        </el-table-column>
    </el-table>
</template>

<script>
import { errLog } from '@/util/index'

export default {
    /**
     * @name: HDW
     * @msg: 基於el-table二次封裝
     * @param {
     *  接收參數:
     *      size                        table size                  |   String
     *      selection                   是否需要多選                 |   Boolean
     *      columns                     表頭                         |   Array
     *      data                        內容                         |   Array
     *      operation                   是否需要操作                  |   Boolean
     *      op-width                    操作寬度                     |   String
     *      expand                      表單嵌套表單                  |   Boolean
     *      op-fixed                    操作固定                      |   string, boolean
     *
     *  el-table 參數 : (v-bind="$attrs") 全部支持
     *
     *  el-table-column 參數:(可自行在columns添加)      默認參數
     *      sortable                                    true, false, 'custom'
     *
     *  columns 參數:
     *          {
     *              title: 'ID',
     *              key: 'id',                  //  頁面展示 row['id']
     *              width: '50px',              //  min-width
     *              slot: 'depot',              //   是否為插槽 value 值為插槽名字
     *              sortable:'custom'
     *          }
     *      ],
     *
     *  el-table 事件: (v-on="listeners") 全部支持
     *      多選監聽(selection)       @selection-change
     *      單選監聽                    @row-click
     *      當前所選行                  @current-change
     *      切換排序                    @sort-change
     *
     *  el-table 方法:(暫未解決 refs 穿透,需自行在 methods 添加)
     *      clearSelection()
     *      toggleRowSelection()
     *      toggleAllSelection()
     *      toggleRowExpansion()
     *      setCurrentRow()
     * }
     *
     */
    name: 'dwCrud',
    // inheritAttrs: true,
    props: {
        size: {
            type: String,
            default: 'mini', // medium / small / mini
        },
        columns: {
            type: Array,
            default: () => [],
        },
        selection: {
            type: Boolean,
            default: false,
        },
        expand: {
            type: Boolean,
            default: false,
        },
        operation: {
            type: Boolean,
            default: true,
        },
        'op-fixed': {
            type: String,
            default: 'right',
        },
        'op-width': {},
    },
    methods: {
        clearSelection() {
            this.$refs['table'].clearSelection()
        },
        toggleRowSelection(row, selected) {
            this.$refs['table'].toggleRowSelection(row, selected)
        },
        toggleAllSelection() {
            this.$refs['table'].toggleAllSelection()
        },
        toggleRowExpansion(row, expanded) {
            this.$refs['table'].toggleRowExpansion(row, expanded)
        },
        setCurrentRow(row) {
            this.$refs['table'].setCurrentRow(row)
        },
        /**
         * 大佬的寫法 (microanswer)
         *
         * obj = {a:{b:{c:1},b1:[2,3,4]}}
         *
         * get(obj,'a.b.c')         // 1
         * get(obj,'a.b1[2]')       // 4
         * get(obj,['a','b','c'])   // 1
         *
         */
        get(obj, key) {
            key = Array.isArray(key) ? key.join('.') : key
            // 方法一 用到了new Funcion()的語法拼接 和 function()()立即執行函數
            return new Function('obj', `return obj${key ? `.${key}` : ''}`)(obj, key)
            // 方法二 eval()
            return eval(`obj${key ? `.${key}` : ''}`)
        },
        // 根據大佬提供的寫法優化
        key2val(row, key) {
            key = Array.isArray(key) ? key.join('.') : key
            let res
            try {
                res = new Function('row', `return row${key ? `.${key}` : ''}`)(row, key)
            } catch (err) {
                errLog('dw-crud', err, 'warn')
                res = null
            }
            return res
        },
        // 以前的思路
        // 根據key找到對應的字段
        old_key2val(row, key) {
            // return this.get(row,key)
            const arr = key.split('.')
            return this.recKey(row, arr)
        },
        // 遞歸key
        recKey(obj, key = []) {
            // 如果是最底層
            if (!key.length) return obj
            // 未到最底層但已是 null/undefined
            if (key.length && !obj) {
                errLog('dw-crud', `${key.join('.')}不存在,請填寫正確的key名`, 'warn')
                return null
            }
            const key0 = key.shift()
            const regObj = this.regKey(key0)
            // 如果匹配出當前key是數組 eg: companies[11]
            if (regObj) {
                const { name, inx } = regObj
                return this.recKey(obj[name][inx], key)
            } else {
                return this.recKey(obj[key0], key)
            }
        },
        // 正則找出 eg: companies[11]
        regKey(key) {
            const reg = /([A-Za-z]+)\[(.*?)\]/g
            // 匹配出 companies(i=1) 和 11(i=2)
            const res = reg.exec(key)
            if (!res) return null
            const name = res[1]
            const inx = res[2]
            return { name, inx }
        },
    },
    mounted() {},
}
</script>

 

 

 

errLog函數

export const errLog = (component, message, status = 'error') => {
    console[status](`[${component} error]:\n${message}`)
}

 

< template >
     < el-table  ref= " table "  v-bind = "$attrs "  v-on = "$listeners "  : size = "size " >
         <!-- 多選框 -->
         < el-table-column  v-if = "selection "  type= " selection "  align= " center "  width= " 55 " / >
         <!-- 表單嵌套 -->
         < el-table-column  v-if = "expand "  type= " expand " >
             < template  slot-scope= " { row, $index } " >
                 < slot  name= " expand "  : row = "row "  : index = "$index " ></ slot >
             </ template >
         </ el-table-column >
         <!-- 文本數據渲染 -->
         < template  v-for = " (column , index )  in columns " >
             < el-table-column  : key = "index "  : min-width = "column .width "  : sortable = "column .sortable "  : prop = "column .key " >
                 <!-- 自定義頭部  slotName.header -->
                 < template  slot= " header "  slot-scope= " { row, $index } " >
                     < slot  v-if = "$scopedSlots [ `${column .slot } .header ` ] "  : name = " `${column .slot } .header ` " ></ slot >
                     < span  v-else >{{ column .title  }}</ span >
                 </ template >

                 <!-- 主體內容 -->
                 < template  slot-scope= " { row, $index } " >
                     <!-- 如果有插槽 -->
                     < slot  v-if = "column .slot "  : name = "column .slot "  : row = "row "  : index = "$index " ></ slot >
                     <!-- 過濾 (暫未完善) -->
                     <!-- <span v-else-if="column.format">{{ key2val(row, column.key) | column.format }}</span> -->
                     <!-- 默認 -->
                     < span  v-else >{{  key2val (row , column .key )  }}</ span >
                 </ template >
             </ el-table-column >
         </ template >
         <!-- 特殊處理的操作布局 默認存在 -->
         < el-table-column  : fixed = "opFixed "  label= " 操作 "  v-if = "operation "  : min-width = "opWidth " >
             < template  slot-scope= " { row, $index } " >
                 < slot  name= " op "  : row = "row "  : index = "$index " ></ slot >
             </ template >
         </ el-table-column >
     </ el-table >
</ template >

< script >
import  { errLog  }  from  ' @/util/index '

export  default  {
     /**
     * @name: HDW
     * @msg: 基於el-table二次封裝
     * @param {
     *  接收參數:
     *      size                        table size                  |   String
     *      selection                   是否需要多選                 |   Boolean
     *      columns                     表頭                         |   Array
     *      data                        內容                         |   Array
     *      operation                   是否需要操作                  |   Boolean
     *      op-width                    操作寬度                     |   String
     *      expand                      表單嵌套表單                  |   Boolean
     *      op-fixed                    操作固定                      |   string, boolean
     *
     *  el-table 參數 : (v-bind="$attrs") 全部支持
     *
     *  el-table-column 參數:(可自行在columns添加)      默認參數
     *      sortable                                    true, false, 'custom'
     *
     *  columns 參數:
     *          {
     *              title: 'ID',
     *              key: 'id',                  //  頁面展示 row['id']
     *              width: '50px',              //  min-width
     *              slot: 'depot',              //   是否為插槽 value 值為插槽名字
     *              sortable:'custom'
     *          }
     *      ],
     *
     *  el-table 事件: (v-on="listeners") 全部支持
     *      多選監聽(selection)       @selection-change
     *      單選監聽                    @row-click
     *      當前所選行                  @current-change
     *      切換排序                    @sort-change
     *
     *  el-table 方法:(暫未解決 refs 穿透,需自行在 methods 添加)
     *      clearSelection()
     *      toggleRowSelection()
     *      toggleAllSelection()
     *      toggleRowExpansion()
     *      setCurrentRow()
     *  }
     *
     */
    name :  ' dwCrud ' ,
     // inheritAttrs: true,
    props :  {
        size :  {
            type :  String ,
            default :  ' mini ' ,  // medium / small / mini
         },
        columns :  {
            type :  Array ,
             default :  ()  =>  [],
         },
        selection :  {
            type :  Boolean ,
            default :  false ,
         },
        expand :  {
            type :  Boolean ,
            default :  false ,
         },
        operation :  {
            type :  Boolean ,
            default :  true ,
         },
         ' op-fixed ' :  {
            type :  String ,
            default :  ' right ' ,
         },
         ' op-width ' :  {},
     },
    methods :  {
         clearSelection ()  {
             this .$refs [ ' table ' ]. clearSelection ()
         },
         toggleRowSelection ( row ,  selected )  {
             this .$refs [ ' table ' ]. toggleRowSelection (row , selected )
         },
         toggleAllSelection ()  {
             this .$refs [ ' table ' ]. toggleAllSelection ()
         },
         toggleRowExpansion ( row ,  expanded )  {
             this .$refs [ ' table ' ]. toggleRowExpansion (row , expanded )
         },
         setCurrentRow ( row )  {
             this .$refs [ ' table ' ]. setCurrentRow (row )
         },
         /**
         * 大佬的寫法 (microanswer)
         *
         * obj = {a:{b:{c:1},b1:[2,3,4]}}
         *
         * get(obj,'a.b.c')         // 1
         * get(obj,'a.b1[2]')       // 4
         * get(obj,['a','b','c'])   // 1
         *
         */
         get ( obj ,  key )  {
            key  =  Array . isArray (key )  ? key . join ( ' . ' )  : key
             // 方法一 用到了new Funcion()的語法拼接 和 function()()立即執行函數
             return  new  Function ( ' obj ' ,  ` return obj ${key   ?   ` . ${key }`   :   '' }` )(obj , key )
             // 方法二 eval()
             return  eval ( ` obj ${key   ?   ` . ${key }`   :   '' }` )
         },
         // 根據大佬提供的寫法優化
         key2val ( row ,  key )  {
            key  =  Array . isArray (key )  ? key . join ( ' . ' )  : key
             let res
             try  {
                res  =  new  Function ( ' row ' ,  ` return row ${key   ?   ` . ${key }`   :   '' }` )(row , key )
             }  catch  (err )  {
                 errLog ( ' dw-crud ' , err ,  ' warn ' )
                res  =  null
             }
             return res
         },
         // 以前的思路
         // 根據key找到對應的字段
         old_key2val ( row ,  key )  {
             // return this.get(row,key)
             const  arr  = key . split ( ' . ' )
             return  this . recKey (row , arr )
         },
         // 遞歸key
         recKey ( obj ,  key  =  [])  {
             // 如果是最底層
             if  ( !key . length )  return obj
             // 未到最底層但已是 null/undefined
             if  (key . length  &&  !obj )  {
                 errLog ( ' dw-crud ' ,  `${key . join ( ' . ' ) } 不存在,請填寫正確的key名 ` ,  ' warn ' )
                 return  null
             }
             const  key0  = key . shift ()
             const  regObj  =  this . regKey (key0 )
             // 如果匹配出當前key是數組 eg: companies[11]
             if  (regObj )  {
                 const  {  name ,  inx  }  = regObj
                 return  this . recKey (obj [name ][inx ], key )
             }  else  {
                 return  this . recKey (obj [key0 ], key )
             }
         },
         // 正則找出 eg: companies[11]
         regKey ( key )  {
             const  reg  =   /( [A-Za-z ] +) \[(. *?) \] /g
             // 匹配出 companies(i=1) 和 11(i=2)
             const  res  = reg . exec (key )
             if  ( !res )  return  null
             const  name  = res [ 1 ]
             const  inx  = res [ 2 ]
             return  { name , inx  }
         },
     },
     mounted ()  {},
}
</ script >


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM