zoukankan      html  css  js  c++  java
  • 基于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',
                         '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']
         *               '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]:
    ${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']
         *               '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>
  • 相关阅读:
    LeetCode 128. 最长连续序列
    MySQL的information_schema
    maven项目板块的pom.xml配置
    mybatis打印SQL日志
    MySQL的时间字段转换
    mysql的csv数据导入与导出
    一致性协议
    分布式事务
    事务基本信息
    分布式系统定义及特点
  • 原文地址:https://www.cnblogs.com/HDWdemo/p/14681638.html
Copyright © 2011-2022 走看看