Skip to content

hf0913/handsontable-vue

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

申明

.[基于 handsontable 二次封装源码]: https://github.com/hf0913/handsontable-vue .[handsontable 官网]: https://handsontable.com/

简要步骤

  1. 原表格标签修改为:Handsontable
  2. 对于 columns,key 或者 data 属性名都可以用来存放后端字段名
  3. 对于 columns 中 type 属性,仅支持:autocomplete、checkbox、date、dropdown、handsontable、numeric、password、text、time,默认为 text,切记不要设置 type 类型为其他值

示例代码

<template>
    <Handsontable
        :checkBox="checkBox"
        :columns="columns"
        v-model="tableData"
        @click="handsontableClick"
        @change="handsontableChange"
        @getCore="getCore"
        @cellDblClick="cellDblClick"
        @getSelectOpts="getSelectOpts"
        :options="options"
        ref="handsontableRef"
    />
</template>

<script>
    export default {
        data() {
            return {
                tableData: [],
                columns: [
                    {
                        key: "checked", // 设置后端字段名
                        type: "checkbox", // 复选框
                        width: 200, // 表格宽度
                        subType: "selection", // 用来挑选行数据,禁止使用title,如果使用了title,就会出现table header没有复选框,只显示 title。
                        openCustomFiter: true // 开启自定义头部筛选
                    },
                    {
                        title: "普通文本", // 表头名
                        key: "text",
                        width: 200,
                        validator: (value, callback) => {
                            // 自定义校验,value为单元格值,callback回调函数,入参为boolean类型。
                            callback(true); // 校验通过
                            callback(false); // 校验失败,单元格背景色标记红色
                        },
                        readOnly: true, // 只读属性,不能被修改。
                        editor: false, // 禁止编辑,但是可以通过粘贴、被填充修改。
                        allowEmpty: true, // 是否可以接受空值
                        openCustomFiter: true // 开启自定义头部筛选
                    },
                    {
                        title: "地址级联选择",
                        data: "address",
                        subType: "address",
                        width: 200,
                        extraField: "maple_address",
                        valueType: "label", // label || value,默认value
                        props: {} // 参考 https://element.eleme.cn/#/zh-CN/component/cascader
                    },
                    {
                        title: "普通级联选择",
                        data: "cascader",
                        subType: "cascader",
                        options: [],
                        extraField: "maple_address",
                        valueType: "label", // label || value,默认value
                        props: {} // 参考 https://element.eleme.cn/#/zh-CN/component/cascader
                    },
                    {
                        title: "时间日期组合",
                        key: "datePicker",
                        subType: "datePicker",
                        width: 200,
                        props: {
                            // 参考 https://element.eleme.cn/#/zh-CN/component/datetime-picker
                            type: "datetime",
                            format: "yyyy-MM-dd HH:mm:ss",
                            valueFormat: "yyyy-MM-dd HH:mm:ss"
                        }
                    },
                    {
                        title: "数字",
                        data: "numeric",
                        type: "numeric",
                        width: 200
                    },
                    {
                        title: "日期",
                        data: "date",
                        type: "date",
                        dateFormat: "YYYY-MM-DD", // 日期类型
                        width: 200
                    },
                    {
                        title: "时间",
                        data: "time",
                        type: "time",
                        timeFormat: "HH:mm", // 时间类型
                        correctFormat: true, // 失去焦点,矫正时间格式
                        width: 200
                    },
                    {
                        title:
                            "下拉框(优化模式,options属性或者source属性,接受一个回调函数,返回数据字典集合)",
                        data: "select",
                        type: "dropdown",
                        // options: () => this.selectArr, // 这种也可以哦,下拉框选项值字段名支持:source || options
                        source: () => this.selectArr, // 存放下拉框选项值集合,每一项中包含值和id,取名source或者options都可以
                        width: 300,
                        // extraField属性:调用getData方法,返回多余字段名,其值取item[valueType === valueName ? labelName : valueName]
                        extraField: "maple_love",
                        valueType: "id", // 配合extraField属性使用,默认等于valueName
                        labelName: "test", // 下拉框选项值集合,每一项中值字段名,默认:label,即用户可以看到下拉框列表显示的值
                        valueName: "id", // 下拉框选项值集合,每一项中id字段名,默认:value,即发送给后台的值,用户是看不到这个值
                        subType: "optimize", // 优化模式,配合maxMatchLen属性一起使用
                        maxMatchLen: 8, // 根据source属性值,模糊匹配最大条数,默认8条,即用户点击下拉框只可以选择8条数据。
                        visibleRows: 4 // 可见列表数量
                    },
                    {
                        title: "下拉框(优化模式)",
                        data: "select",
                        type: "dropdown",
                        source: [],
                        width: 300,
                        extraField: "maple_love",
                        valueType: "id",
                        labelName: "test",
                        valueName: "id",
                        subType: "optimize",
                        maxMatchLen: 8
                    },
                    {
                        title: "下拉框(自定义请求ajax)",
                        data: "selectAjax",
                        type: "dropdown",
                        source: [],
                        width: 300,
                        extraField: "maple_love",
                        valueType: "id",
                        labelName: "test",
                        valueName: "id",
                        subType: "ajax", // 自定义ajax请求,在编辑业务场景中数据回显,请必须请求一次数据,并将数据赋值给source属性。
                        ajaxConfig: {
                            // ajax请求配置
                            url: "http://www.maplehu.com.cn/api/login", // 请求后端的完整地址,切记不能携带任何请求参数。
                            method: "post", // 请求方式
                            queryField: "query", // 查询字段名,动态获取查询值value
                            data: {
                                // 请求参数以body形式发送,如果不需要请设置data属性。
                                login_name: "admin",
                                password: "123456",
                                query: "test"
                            },
                            // param:{} // 请求参数从url携带发送,查询参数,场景业务场景如get请求
                            result: "res.data.data" // 根据后端返回关于下拉框选项集合的数据结构,给出一个字段访问链。必须滴。
                        }
                    },
                    {
                        title: "操作",
                        subType: "handle", // 操作模式
                        width: 140,
                        options: [
                            {
                                name: "复制", // 文本标题
                                color: "#409eff" // 文本颜色
                            },
                            {
                                name: "添加",
                                color: "#67c23a"
                            },
                            {
                                name: "删除",
                                color: "#f56c6c"
                            }
                        ]
                    }
                ],
                options: {
                    // 更多options,https://handsontable.com/docs/7.4.2/Options.html
                    maxRows: 12080, // 数据上限
                    minRows: 8, // 至少8条,如果设置该属性,请删除与之冲突的补偿数据的代码。
                    height: 400,
                    readOnly: false, // table是否只读
                    hiddenColumns: {
                        // 隐藏某些列,接受列号的数组
                        columns: []
                    },
                    columnSorting: true, // 开启排序
                    wordWrap: false, // 不换行
                    nestedHeaders: [
                        // 合并表头
                        ["A", { label: "B", colspan: 8 }, "C"],
                        [
                            "D",
                            { label: "E", colspan: 4 },
                            { label: "F", colspan: 4 },
                            "G"
                        ],
                        [
                            "H",
                            { label: "I", colspan: 2 },
                            { label: "J", colspan: 2 },
                            { label: "K", colspan: 2 },
                            { label: "L", colspan: 2 },
                            "M"
                        ],
                        ["N", "O", "P", "Q", "R", "S", "T", "U", "V", "W"]
                    ],
                    cells: (row, column, prop) => {
                        // 控制一个或多个单元格属性
                        // row:行号, column:列号, prop:字段名
                        const cellProperties = {};

                        if (row === this.myValue.length - 1) {
                            // 行号等于最后一行
                            cellProperties.readOnly = true; // 单元格只读
                            cellProperties.comment = {
                                // 单元格备注
                                value: "备注内容", // 单元格备注内容
                                readOnly: true // 备注内容只读
                            };
                        }
                        if (row === this.core.countRows() - 1) {
                            cellProperties.readOnly = true;
                        } // 专为表尾合计用,如果使用了表尾合计,请一定要加上此段代码
                        return cellProperties;
                    },
                    columnSummary: [
                        // 表尾合计
                        {
                            key: "n1", // 需要统计某列的字段名
                            type: "sum" // 目前暂时仅支持sum类型(求和)
                        },
                        {
                            key: "n2",
                            type: "sum"
                        }
                    ],
                    openEmptyValid: true, // 是否开启空行校验,默认开启
                    hasDefaultValFileds: ["字段一", "字段二"], // 是否存在默认值的字段集合,在getData数据校验空行会综合考虑是否标记单元格红色
                    multiColumnSorting: true, // 开启排序
                    multiColumnSorting: {
                        // 排序配置
                        initialConfig: [
                            {
                                column: 1,
                                sortOrder: "asc" // 正序
                            },
                            {
                                column: 0,
                                sortOrder: "desc" // 反序
                            }
                        ]
                    },
                    customValidate: ({ isValid, value, row, key }) => {
                        // 全局自定义校验回调函数
                        // isValid:当前单元格校验状态,value:当前单元格值,row:当前单元格行号,key:当前单元格字段名
                        return true; // true即校验通过,false即校验失败
                    },
                    customCellDblClick: ({ row, col, $el, core }) => {
                        // 自定义双击单元格回调函数
                        // row:行号,col:列号,$el:当前单元格dom
                        return true; // true即通过,false即阻止
                    }
                },
                core: Object, // https://handsontable.com/docs/7.4.2/Core.html
                checkBox: {
                    // 表头中全选checkBox必须配置
                    key: "checkbox", // 复选框字段名
                    col: 0 // 复选框行号
                }
            };
        },
        methods: {
            getCore(v) {
                // 获取core
                this.core = v;
            },
            handsontableChange(o) {
                // change事件,通用模版
                // getKeyChange, filterKeysChanges方法二选一,个人建议filterKeysChanges方法,第三个参数是否过滤监听合计一行数据变化,默认是true,即过滤
                // row:行号 key:字段名 oldVal:旧值 newVal:新值 changes:单元格数据修改的集合
                // changeCurrentCell 修改当前监听的单元格值
                // filterSummaryRow: 过滤监听合计一行的数据变化,默认是true,即过滤
                // checked:勾选数据集合,复选框触发
                const {
                    getKeyChange,
                    filterKeysChanges,
                    changes = [[]],
                    changeCurrentCell,
                    checked
                } = o;

                getKeyChange("你需要监听的字段名1", changes, true).map(
                    ([row, key, oldVal, newVal]) => {
                        console.log(row, key, oldVal, newVal);
                    }
                );
                getKeyChange("你需要监听的字段名2", changes, true).map(
                    ([row, key, oldVal, newVal]) => {
                        console.log(row, key, oldVal, newVal);
                    }
                );

                filterKeysChanges({
                    filterSummaryRow: true, // 过滤监听合计一行的数据变化,默认是true,即过滤
                    changes,
                    keys: ["你需要监听的字段名1", "你需要监听的字段名2"],
                    callback: ({
                        row,
                        key,
                        oldVal,
                        newVal,
                        changeCurrentCell,
                        index
                    }) => {
                        console.log(row, key, oldVal, newVal, index);
                        // changeCurrentCell[3] = 'maple test'
                    }
                });
            },
            handsontableClick(o) {
                console.log(o, "点击事件");
            },
            /**
             * @description getData方法是一个promise,该方法会去遍历table数据,在遍历到每一个item,都会触发一个回调函数,该回调函数会提供两个参数(item,index),并接受一个对象,该对象会被浅合并到当前item。
             */
            getData() {
                // 如果不需要任何校验,可以不需要调用该函数
                this.$refs.handsontableRef
                    .getData((item, index) => {
                        item = {
                            ...item,
                            notAddabled: false, // 是否不添加当前item数据,false即添加,true即不添加
                            maple: index // 基于item合并新属性
                        };
                        return item;
                    })
                    .then(({ value, valid, columns }) => {
                        // valid 校验状态,true即通过
                        console.log(value, valid, columns);
                    });
            },
            /**
             * @description  单元格双击事件
             */
            cellDblClick({ coord, mouseEvent, $el }) {
                console.log(coord, mouseEvent, $el);
            },
            /**
             * @description  获取下拉框列表变化
             */
            getSelectOpts({ index, query, key, options }) {
                console.log(index, query, key, options);
                // index:columns中的索引,query:查询值,key:字段名,options:下拉框选项值
            },
            utils() {
                // 工具方法 https://github.com/hf0913/vue-handsontable-element/blob/master/src/utils/index.js
                return utils;
            }
        }
    };
</script>

#### 使用说明

1. 关于下拉框,建议使用【title: "下拉框(优化模式,options 属性或者 source 属性,接受一个回调函数,返回数据字典集合)"】这种类型
2. 获取某一个单元格值:this.core.getDataAtCell(row,col)
3. 获取某一行数据:this.core.getDataAtRow(row)
4. 获取某一列数据:this.core.getDataAtCol(col)
5. 折叠行,https://handsontable.com/docs/8.0.0/demo-nested-rows.html
6. 设置某一个单元格的值:this.core.setDataAtCell(row, col, value, '标记'),强烈不建议用在批量修改数据
7. 关于 core 获取,可以通过@getCore 方法,查看上面的示例代码,change 方法和 click 方法也会返回 core 对象
8. 请勿使用 setTimeout 来达到视图层更新
9. 修改数据,如果视图没有响应式渲染,请调用 this.core.updateSettings({data: data})

##### 注意事项

全局修改该组件样式,会影响严重组件布局与功能,切记~

About

Tables support editing

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published