ele复杂表操作

624 阅读1分钟

饿了么UI框架合并表头&合并行&拖拽序号&添加总计

  • 复杂的表合并
    • span-method:合并行或列的计算方法
    • 合并行服务端排序(默认正序 倒序要加reverse
    • summary-method & show-summary:添加合计
    • cell-class-name:给指定列添加 text 类
    • row-key:唯一的值 (解决拖拽序号顺序混乱的问题)

优化合并表头循环(推荐)

  • 效果图

image.png

<template>
    <div>
        <!-- 表 -->
        <el-table
            :data="tableData"
            border
            ref="ref-table"
            :height="tableHeight"
            size="mini"
            row-key="num"
            :cell-class-name="({columnIndex }) => columnIndex == 0 ? 'text' : ''"
            :span-method="objectSpanMethod"
            :summary-method="getSummaries"
            show-summary
        >
            <el-table-column
                align="center"
                label="序号"
                width="80px"
            >
                <template slot-scope="scope">
                    {{scope.$index +1}}
                </template>
            </el-table-column>
            <!-- 不合并表头 -->
            <template  v-for="(value, key) in tableHeader">
                <el-table-column
                    v-if="!combineKeys.includes(key)"
                    align="center"
                    :key="key"
                    :prop="key"
                    :label="value"
                >
                    <!-- 表头操作 -->
                    <template slot="header" v-if="key === 'name'">
                        <!-- 添加提示 -->
                        <el-tooltip
                            class="item"
                            effect="light"
                            placement="top"
                        >
                            <span
                                slot="content"
                            >
                                提示啦
                            </span>
                            <span>
                                {{value}}
                                <i class="el-icon-question"></i>
                            </span>
                        </el-tooltip>
                    </template>
                </el-table-column>
            </template>
            <!-- 合并表头 -->
            <template v-for="item in combineHeader">
                <el-table-column
                    align="center"
                    :key="item.title"
                    :prop="item.title"
                    :label="item.title"
                >
                    <el-table-column
                        v-for="(n) in item.column"
                        :key="n.field"
                        :prop="n.field"
                        :label="n.title"
                        align="center"
                    >
                    </el-table-column>
                </el-table-column>
            </template>
        </el-table>
    </div>
</template>

<script>
// Sortable实现表拖拽功能
import Sortable from 'sortablejs';
export default {
    name: 'RecordPageDetail',
    data() {
        return {
            tableHeight: 'auto', // 表高度
            tableData: [
                { first_name: '韩', last_name: '信', add: '12-11', num: '小明', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-12', num: '小李', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-13', num: '小红', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-14', num: '小波', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-15', num: '小波1', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-16', num: '小波2', name: '测试', sort: '8' },
                { first_name: '韩', last_name: '信', add: '12-16', num: '小波3', name: '测试', sort: '8' }
            ], // 表
            tableHeader: {
                add: '日期',
                num: '审核人',
                first_name: '姓',
                last_name: '名',
                sort: '数量1',
                name: '名字'
            }, // 表头
            combineHeader: [{
                title: '姓名',
                column: [{field: 'first_name', title: '姓' }, { field: 'last_name', title: '名' }]
            }, {
                title: '年龄',
                column: [{ field: 'sort', title: '排序' }, { field: 'name', title: '名字' }]
            }], // 合并表头
            combineKeys: ['first_name', 'last_name', 'name', 'sort'], // 合并的key值
            totalData: {add: '12-11~12-12', first_name: 'NaN', sort: '32'} // 合并行的数据
        };
    },
    mounted() {
        this.row_drag();
    },
    methods: {
        // table通过序号拖拽行
        row_drag() {
            const _tbody = document.querySelector('.el-table__body-wrapper tbody');
            const _self = this;
            Sortable.create(_tbody, {
                animation: 150, // ms, number 单位:ms,定义排序动画的时间
                handle: '.text', // 使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动
                onEnd({ newIndex, oldIndex }) {
                    const _targetRow = _self.tableData.splice(oldIndex, 1)[0];
                    _self.tableData.splice(newIndex, 0, _targetRow);
                }
            });
        },
        // 合并行
        objectSpanMethod({ rowIndex, columnIndex }) {
            const _keyMap = this.formatRowspanAndColspan(this.tableData, 'add');
            if (columnIndex === 1) {
                return {
                    rowspan: _keyMap[rowIndex],
                    colspan: 1
                };
            }
        },
        // 通过传入的key计算
        formatRowspanAndColspan(tableData, key) {
            const _basic = [];
            const _computedMap = [];
            // 拿到需要的这一列的所有数据
            tableData.forEach(t => _basic.push(t[key]));
            // 计算出每种数据需要的个数
            _basic.forEach((t, index) => {
                _computedMap[t] = _computedMap[t] ? _computedMap[t] + 1 : 1;
            });
            // 在Object.values(_computedMap).后面添加反转函数解决时间倒序合并行出错的问题
            return Object.values(_computedMap).reduce((result, current) => {
                return [...result, current, ...[...new Array(current - 1)].map(() => 0)];
            }, []);
        },
        // 总计
        getSummaries(param) {
            const { columns } = param;
            const _sums = [];
            columns.forEach((column, index) => {
                // 第一行设置为总计
                if (index === 0) {
                    _sums[index] = '总计';
                }
                const _tottalArr = Object.entries(this.totalData || {}); // 表格数据 总计
                _tottalArr.forEach((item, index2) => {
                    // column.property为key值
                    if (column.property === item[0]){
                        _sums[index] = item[1];
                    }
                });
            });
            return _sums;
        }
    }
};
</script>

饿了么table(带有展开子表) + Sortable

  • Sortablejs+element树形表格 拖拽
  • :key="tableKey":用于拖拽刷新dom
<template>
    <div class="row padding">
        <!-- 表单 -->
        <el-form ref="ref-validateForm" :rules="rules" :model="applyForm">
            <!-- 表 -->
            <el-table
                :data="applyForm.tableData"
                border
                ref="ref-table"
                v-loading="$store.state.global.tableLoadingStatus"
                :height="tableHeight"
                row-key="num"
                :cell-class-name="({ columnIndex }) => columnIndex == 1 ? 'sortable-id' : ''"
                :row-class-name="setClassName"
                :key="tableKey"
                @expand-change="init_child_data"
            >
                <!-- 下拉表 -->
                <el-table-column
                    type="expand"
                >
                    <template slot-scope="props">
                        <div class="child-table">
                            <el-table
                                :data="props.row.childyList"
                                ref="ref-table-child"
                                size="mini"
                                border
                            >
                               <el-table-column
                                    align="center"
                                    :label="value"
                                    :prop="key"
                                    v-for="(value, key) in child"
                                    :key="key"
                                >
                                    <template slot-scope="scope">
                                        <template v-if="['num'].includes(key)">
                                            测试啦
                                        </template>
                                        <template v-else>
                                          {{scope.row[key]}}
                                        </template>
                                    </template>
                                </el-table-column>
                            </el-table>
                            <el-pagination
                                small
                                @current-change="search_data(props.row)"
                                :current-page.sync="props.row.pageConfig.page"
                                layout="total, prev, pager, next, jumper"
                                :page-size="parseInt(props.row.pageConfig.page_size)"
                                :total="parseInt(props.row.pageConfig.count)"
                            >
                            </el-pagination>
                        </div>
                    </template>
                 </el-table-column>
                <!-- 拖动序号排序 -->
                <el-table-column
                    align="center"
                    width="80"
                    label="排序"
                >
                    <template slot-scope="scope">
                        {{scope.$index +1}}
                    </template>
                </el-table-column>
                <el-table-column
                    align="center"
                    v-for="(value, key) in tableHeader"
                    :key="key"
                    :width="set_table_col_width(key)"
                    :prop="key"
                    :label="value"
                >
                    <template slot-scope="scope">
                         <template v-if="['add', 'first_name', 'last_name', 'sort'].includes(key)">
                            <template v-if="scope.row.isEdit">
                                <template v-if="['add'].includes(key)">
                                    <el-form-item :prop="'tableData.' + scope.$index + '.add'" :rules="rules.add">
                                        <el-select
                                            v-model="scope.row.index"
                                            placeholder="请选择"
                                            clearable
                                        >
                                            <el-option
                                                v-for="option in list"
                                                :key="option.value"
                                                :label="option.label"
                                                :value="option.value"
                                            >
                                            </el-option>
                                        </el-select>
                                    </el-form-item>
                                </template>
                                <template v-if="['sort'].includes(key)">
                                    <el-form-item :prop="'tableData.' + scope.$index + '.sort'" :rules="rules.sort">
                                        <el-input
                                            v-model="scope.row.sort"
                                            placeholder="测试啦"
                                            type="number"
                                        ></el-input>
                                    </el-form-item>
                                </template>
                                <template v-if="['first_name'].includes(key)">
                                    <el-form-item
                                        :prop="'tableData.' + scope.$index + '.first_name'"
                                        :rules="rules.first_name">
                                        <el-input
                                            v-model="scope.row.first_name"
                                            placeholder="测试啦"
                                            type="text"
                                        ></el-input>
                                    </el-form-item>
                                </template>
                                <template v-if="['last_name'].includes(key)">
                                    <el-form-item
                                        :prop="'tableData.' + scope.$index + '.last_name'"
                                        :rules="rules.last_name">
                                        <el-input
                                            v-model="scope.row.last_name"
                                            placeholder="测试啦"
                                            type="text"
                                        ></el-input>
                                    </el-form-item>
                                </template>
                            </template>
                            <template v-else>
                                 {{scope.row[key]}}
                            </template>
                         </template>
                         <template v-else>
                           {{scope.row[key]}}
                         </template>
                    </template>
                </el-table-column>
                <!-- 操作 -->
                <el-table-column
                align="center"
                width="150"
                label="操作"
                >
                    <template slot-scope="scope">
                        <template v-if="scope.row.isEdit">
                            <el-button size="mini" type="text" @click="handle_save(scope.row)">保存</el-button>
                        </template>
                        <template v-else>
                            <el-button size="mini" type="text" @click="handle_edit(scope.row)">修改</el-button>
                        </template>
                    </template>
                </el-table-column>
            </el-table>
        </el-form>
    </div>
</template>

<script>
import Sortable from 'sortablejs';

export default {
    name: 'CourseConfiguration',
    data() {
        return {
            tableKey: '', // 用于拖拽刷新dom
            applyForm: {
                tableData: [
                    { expand: true, index: '1', first_name: '韩', last_name: '信', add: 'aaa', num: '小明1', name: '测试', sort: '8', childyList: [
                        { index: '1', add: '1', num: '小明', name: '测试1', sort: '8' },
                        { index: '2', add: '2', num: '小李', name: '测试1', sort: '8' },
                        { index: '3', add: '3', num: '小红', name: '测试1', sort: '8' }
                    ]},
                    { expand: false, index: '2', first_name: '韩', last_name: '信', add: 'bbb', num: '小李2', name: '测试', sort: '8' },
                    { expand: true, index: '3', first_name: '韩', last_name: '信', add: 'ccc', num: '小红3', name: '测试', sort: '8', childyList: [
                        { index: '1', add: '1', num: '小明', name: '测试2', sort: '8' },
                        { index: '2', add: '2', num: '小李', name: '测试2', sort: '8' },
                        { index: '3', add: '3', num: '小红', name: '测试2', sort: '8' }
                    ]},
                    { expand: false, index: '1', first_name: '韩', last_name: '信', add: 'aaa', num: '小波4', name: '测试', sort: '8' },
                    { expand: true, index: '2', first_name: '韩', last_name: '信', add: 'bbb', num: '小波5', name: '测试', sort: '8', childyList: [
                        { index: '1', add: '1', num: '小明', name: '测试3', sort: '8' },
                        { index: '2', add: '2', num: '小李', name: '测试3', sort: '8' },
                        { index: '3', add: '3', num: '小红', name: '测试3', sort: '8' }
                    ]},
                    { expand: false, index: '3', first_name: '韩', last_name: '信', add: 'ccc', num: '小波6', name: '测试', sort: '8' },
                    { expand: false, index: '3', first_name: '韩', last_name: '信', add: 'ccc', num: '小波7', name: '测试', sort: '8' }
                ] // 表
            },
            tableHeader: {
                add: '日期',
                num: '审核人',
                first_name: '姓',
                last_name: '名',
                sort: '数量1',
                name: '名字'
            }, // 表头
            rules: {
                add: { required: true, trigger: ['change', 'blur'] },
                first_name: { required: true, trigger: ['change', 'blur'] },
                last_name: { required: true, trigger: ['change', 'blur'] }
            }, // 表单验证
            tableHeight: 'auto', // 表高度
            isEdit: '', // 是否编辑
            list: [
                { label: 'aaa', value: '1'},
                { label: 'bbb', value: '2'},
                { label: 'ccc', value: '3'}
            ],
            child: {
                add: '日期',
                num: '审核人',
                sort: '数量1',
                name: '名字',
                index: '排序'
            }
        };
    },
    mounted() {
        this.row_drag();
    },
    methods: {
        // table通过序号拖拽行
        row_drag() {
            this.$nextTick(() => {
                const _tbody = document.querySelector('.el-table__body-wrapper tbody');
                const _self = this;
                Sortable.create(_tbody, {
                    animation: 150, // ms, number 单位:ms,定义排序动画的时间
                    handle: '.sortable-id', // 使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动
                    onEnd({ newIndex, oldIndex }) {
                        const _targetRow = _self.applyForm.tableData.splice(oldIndex, 1)[0];
                        _self.applyForm.tableData.splice(newIndex, 0, _targetRow);
                        _self.sortMenuData(); // 调用刷新dom
                    }
                });
            });
        },
        // 刷新dom再次调用拖拽的功能
        sortMenuData() {
            // 刷新dom
            this.tableKey = Math.random();
            this.row_drag();
        },
        // 设置表格列宽度
        set_table_col_width(key) {
            const _obj = {
            };
            return _obj[key] || '';
        },
        // 保存
        handle_save(row) {
            this.$set(row, 'isEdit', false);
            if (this.$refs['ref-validateForm']) {
                this.$refs['ref-validateForm'].validate(valid => {
                    if (valid) {
                        console.log(row);
                        this.$message.success('保存成功');
                    } else {
                        this.$set(row, 'isEdit', true);
                        this.$message.error('表单需填写完整!');
                    }
                });
            }
        },
        // 修改
        handle_edit(row) {
            this.$set(row, 'isEdit', true);
        },
        // 通过样式隐藏展开行 需要服务端返回是否展开行
        setClassName({row, index}){
            return row.expand ? '' : 'expand';
        },
        // 获取子列表
        init_child_data(row) {}
        // 筛选项
        search_data(row) {
            this.init_child_data(row);
        }
    }
};
</script>

<style lang="scss" scoped>
.el-form .el-form-item--mini.el-form-item {
    margin: 0px;
}
::v-deep .el-table .expand .cell .el-table__expand-icon {
	display: none;
}
.child-table{
    padding: 10px;
    width: 600px;
}
</style>

image.png