zoukankan      html  css  js  c++  java
  • handsontable多选下拉框编辑器扩展

    一、效果截图

     

     二、文件引用

    多选下拉框扩展自handsontable的BaseEditor。

    多选下拉框组件由两个文件构成,

    • 一个下拉框样式表MultiSelect.css
    • 一个组件实现脚本MultiSelect.js

    使用时引用这两个文件即可,当然,要先在你的页面中引用handsontable的核心js文件,再引用我这两个文件。

    其中js以模块类型引用(type="module"

    <link href="../../Scripts/MultiSelect.css" rel="stylesheet" />
    <script type="module" src="../../Scripts/MultiSelect.js"></script>

    三、使用范例

    var columns = [
                   { data: 'field1', title: 'title1',  120, className: 'htCenter htMiddle', editor: 'MultiSelect', selectOptions: ['1#', '2#', '3#', '4#', '5#', '6#', '7#', '8#'] }
                ];

    四、源代码

    1.MultiSelect.js

    /// <reference path="handsontable.full.min.js" />
    
    //封闭在IIFE中
    (Handsontable => {
        class MultiSelectEditor extends Handsontable.editors.BaseEditor {
    
            // ...rest of the editor code
            /**
            * Initializes editor instance, DOM Element and mount hooks.
            * 初始化编辑器实例,dom元素和挂载钩子函数
            */
            init() {
                // Create detached node, add CSS class and make sure its not visible
                //增加触发节点,增加class类并确保节点隐藏隐藏
                var MultiSelectDomContainer = document.createElement("div");
                MultiSelectDomContainer.style.paddingTop = "30px";
                this.select = MultiSelectDomContainer;
                Handsontable.dom.addClass(this.select, 'htMultiSelectEditor');
                this.select.style.display = 'none';
    
                // Attach node to DOM, by appending it to the container holding the table
                this.hot.rootElement.appendChild(this.select);
            }
    
            //编辑器的值加载到单元格
            getValue() {
                var selects = "";
                var childs = this.select.children;
                for (var i = 0; i < childs.length; i++) {
                    if (childs[i].children[0].checked == true) {
                        selects += "["+childs[i].children[1].innerHTML+"]";
                    }
                }
                return selects;
                return this.select;
                return "";
            }
    
            //单元格的值加载到编辑器
            setValue(value) {
                var selectCount = 0;
                var selects = value.split("][");
                var childs = this.select.children;
                for (var i = 0; i < selects.length; i++) {
                    selects[i]=selects[i].replace("[", "").replace("]", "");
    
                    for (var j = 0; j < childs.length; j++) {
                        if (childs[j].value == selects[i]) {
                            selectCount += 1;
                            childs[j].children[0].checked = true;
                        }
                    }
                }
                //this.select.style.paddingTop = selectCount*30+"px";
            }
    
            //打开编辑器
            open() {
                this._opened = true;
                this.refreshDimensions();
                this.select.style.display = '';
            }
    
            //编辑器样式计算
            refreshDimensions() {
                this.TD = this.getEditedCell();
    
                // TD is outside of the viewport.
                if (!this.TD) {
                    this.close();
    
                    return;
                }
                //调整弹出框位置,使其位于单元格下面
                this.select.style.paddingTop = this.TD.clientHeight + "px";
    
                const { wtOverlays } = this.hot.view.wt;
                const currentOffset = Handsontable.dom.offset(this.TD);
                const containerOffset = Handsontable.dom.offset(this.hot.rootElement);
                const scrollableContainer = wtOverlays.scrollableElement;
                const editorSection = this.checkEditorSection();
                let width = Handsontable.dom.outerWidth(this.TD) + 1;
                let height = Handsontable.dom.outerHeight(this.TD) + 1;
                let editTop = currentOffset.top - containerOffset.top - 1 - (scrollableContainer.scrollTop || 0);
                let editLeft = currentOffset.left - containerOffset.left - 1 - (scrollableContainer.scrollLeft || 0);
                let cssTransformOffset;
    
                switch (editorSection) {
                    case 'top':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.topOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'left':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.leftOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'top-left-corner':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.topLeftCornerOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'bottom-left-corner':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.bottomLeftCornerOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'bottom':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.bottomOverlay.clone.wtTable.holder.parentNode);
                        break;
                    default:
                        break;
                }
    
                if (this.hot.getSelectedLast()[0] === 0) {
                    editTop += 1;
                }
                if (this.hot.getSelectedLast()[1] === 0) {
                    editLeft += 1;
                }
    
                const selectStyle = this.select.style;
    
                if (cssTransformOffset && cssTransformOffset !== -1) {
                    selectStyle[cssTransformOffset[0]] = cssTransformOffset[1];
                } else {
                    Handsontable.dom.resetCssTransform(this.select);
                }
    
                const cellComputedStyle = Handsontable.dom.getComputedStyle(this.TD, this.hot.rootWindow);
    
                if (parseInt(cellComputedStyle.borderTopWidth, 10) > 0) {
                    height -= 1;
                }
                if (parseInt(cellComputedStyle.borderLeftWidth, 10) > 0) {
                    width -= 1;
                }
    
                selectStyle.height = `${height}px`;
                selectStyle.minWidth = `${width}px`;
                selectStyle.top = `${editTop}px`;
                selectStyle.left = `${editLeft}px`;
                selectStyle.margin = '0px';
            }
    
            //获取当前单元格
            getEditedCell() {
                const { wtOverlays } = this.hot.view.wt;
                const editorSection = this.checkEditorSection();
                let editedCell;
    
                switch (editorSection) {
                    case 'top':
                        editedCell = wtOverlays.topOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 101;
                        break;
                    case 'corner':
                        editedCell = wtOverlays.topLeftCornerOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 103;
                        break;
                    case 'left':
                        editedCell = wtOverlays.leftOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 102;
                        break;
                    default:
                        editedCell = this.hot.getCell(this.row, this.col);
                        this.select.style.zIndex = '';
                        break;
                }
    
                return editedCell < 0 ? void 0 : editedCell;
            }
    
            focus() {
                this.select.focus();
            }
    
            close() {
                this._opened = false;
                this.select.style.display = 'none';
            }
    
            //读取选项配置到编辑器
            prepare(row, col, prop, td, originalValue, cellProperties) {
                // Remember to invoke parent's method
                super.prepare(row, col, prop, td, originalValue, cellProperties);
                const selectOptions = this.cellProperties.selectOptions;
                let options;
    
                if (typeof selectOptions === 'function') {
                    options = this.prepareOptions(selectOptions(this.row, this.col, this.prop));
                } else {
                    options = this.prepareOptions(selectOptions);
                }
    
                Handsontable.dom.empty(this.select);
    
                Handsontable.helper.objectEach(options, (value, key) => {
                    const optionElement = this.hot.rootDocument.createElement('div');
    
                    const checkbox = this.hot.rootDocument.createElement('input');
                    checkbox.type = "checkbox";
                    optionElement.appendChild(checkbox);
    
                    var textSpan = this.hot.rootDocument.createElement('span');
                    textSpan.innerHTML = value;
                    optionElement.appendChild(textSpan);
    
                    optionElement.value = key;
    
                    Handsontable.dom.addClass(optionElement, 'MultiSelectOption');
    
                    //Handsontable.dom.fastInnerHTML(optionElement, value);
                    this.select.appendChild(optionElement);
                });
            }
            prepareOptions(optionsToPrepare) {
                let preparedOptions = {};
    
                if (Array.isArray(optionsToPrepare)) {
                    for (let i = 0, len = optionsToPrepare.length; i < len; i++) {
                        preparedOptions[optionsToPrepare[i]] = optionsToPrepare[i];
                    }
    
                } else if (typeof optionsToPrepare === 'object') {
                    preparedOptions = optionsToPrepare;
                }
    
                return preparedOptions;
            }
        }
    
    
        // Put editor in dedicated namespace
        //将编辑器添加到专用命名空间
        Handsontable.editors.MultiSelectEditor = MultiSelectEditor;
        // Register alias
        //编辑器注册别名
        Handsontable.editors.registerEditor('MultiSelect', MultiSelectEditor);
    
    })(Handsontable);
    MultiSelect.js

    2.MultiSelect.css

    .htMultiSelectEditor {
        /*
      * This hack enables to change <select> dimensions in WebKit browsers
      */
        -webkit-appearance: menulist-button !important;
        position: absolute;
        width: auto;
    }
    .MultiSelectOption:hover{
        background-color:antiquewhite;
        border:1px solid gray;
    }
    MultiSelect.css

     五、更新

    日期:2022-01-10

    问题

    • 修改样式
    • 解决在表格底部,弹出的下拉框被遮挡的问题

    1.MutiSelect.js

    /// <reference path="handsontable.full.min.js" />
    
    //封闭在IIFE中
    (Handsontable => {
        class MultiSelectEditor extends Handsontable.editors.BaseEditor {
    
            // ...rest of the editor code
            /**
            * Initializes editor instance, DOM Element and mount hooks.
            * 初始化编辑器实例,dom元素和挂载钩子函数
            */
            init() {
                // Create detached node, add CSS class and make sure its not visible
                //增加触发节点,增加class类并确保节点隐藏隐藏
                var MultiSelectDomContainer = document.createElement("div");
                MultiSelectDomContainer.style.paddingTop = "30px";
                this.select = MultiSelectDomContainer;
                Handsontable.dom.addClass(this.select, 'htMultiSelectEditor');
                this.select.style.display = 'none';
    
                // Attach node to DOM, by appending it to the container holding the table
                //this.hot.rootElement.appendChild(this.select);//当前单元格的下拉框子节点(会被遮挡)
                this.hot.rootDocument.body.appendChild(this.select);//文档的下拉框子节点(不会被遮挡)
                this.select.addEventListener("mousedown", (
                    function (e) {
                        return e.stopPropagation();
                    }));//阻止单光获得值在下拉框元素上面,editermanager的点击事件执行(关闭下拉框),让单元格能获得值
                //document.body.appendChild(this.select);
            }
    
            //编辑器的值加载到单元格
            getValue() {
                var selects = "";
                var childs = this.select.children;
                for (var i = 0; i < childs.length; i++) {
                    if (childs[i].children[0].checked == true) {
                        selects += "["+childs[i].children[1].innerHTML+"]";
                    }
                }
                return selects;
                return this.select;
                return "";
            }
    
            //单元格的值加载到编辑器
            setValue(value) {
                var selectCount = 0;
                var selects = value.split("][");
                var childs = this.select.children;
                for (var i = 0; i < selects.length; i++) {
                    selects[i]=selects[i].replace("[", "").replace("]", "");
    
                    for (var j = 0; j < childs.length; j++) {
                        if (childs[j].value == selects[i]) {
                            selectCount += 1;
                            childs[j].children[0].checked = true;
                        }
                    }
                }
                //this.select.style.paddingTop = selectCount*30+"px";
            }
    
            //打开编辑器
            open() {
                this._opened = true;
                this.refreshDimensions();
                this.select.style.display = '';
            }
    
            //编辑器样式计算
            refreshDimensions() {
                this.TD = this.getEditedCell();
    
                // TD is outside of the viewport.
                if (!this.TD) {
                    this.close();
    
                    return;
                }
                //调整弹出框位置,使其位于单元格下面
                this.select.style.paddingTop = this.TD.clientHeight + "px";
    
                const { wtOverlays } = this.hot.view.wt;
                const currentOffset = Handsontable.dom.offset(this.TD);
                const containerOffset = Handsontable.dom.offset(this.hot.rootElement);
                const scrollableContainer = wtOverlays.scrollableElement;
                const editorSection = this.checkEditorSection();
                let width = Handsontable.dom.outerWidth(this.TD) + 1;
                let height = Handsontable.dom.outerHeight(this.TD) + 1;
                let editTop = currentOffset.top - containerOffset.top - 1 - (scrollableContainer.scrollTop || 0);
                let editLeft = currentOffset.left - containerOffset.left - 0 - (scrollableContainer.scrollLeft || 0);
                let cssTransformOffset;
    
                switch (editorSection) {
                    case 'top':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.topOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'left':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.leftOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'top-left-corner':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.topLeftCornerOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'bottom-left-corner':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.bottomLeftCornerOverlay.clone.wtTable.holder.parentNode);
                        break;
                    case 'bottom':
                        cssTransformOffset = Handsontable.dom.getCssTransform(wtOverlays.bottomOverlay.clone.wtTable.holder.parentNode);
                        break;
                    default:
                        break;
                }
    
                if (this.hot.getSelectedLast()[0] === 0) {
                    editTop += 1;
                }
                if (this.hot.getSelectedLast()[1] === 0) {
                    editLeft += 1;
                }
    
                const selectStyle = this.select.style;
    
                if (cssTransformOffset && cssTransformOffset !== -1) {
                    selectStyle[cssTransformOffset[0]] = cssTransformOffset[1];
                } else {
                    Handsontable.dom.resetCssTransform(this.select);
                }
    
                const cellComputedStyle = Handsontable.dom.getComputedStyle(this.TD, this.hot.rootWindow);
    
                if (parseInt(cellComputedStyle.borderTopWidth, 10) > 0) {
                    height -= 1;
                }
                if (parseInt(cellComputedStyle.borderLeftWidth, 10) > 0) {
                    width -= 1;
                }
    
                //selectStyle.height = `${height}px`;
                selectStyle.height = "auto";
                selectStyle.minWidth = `${width}px`;
                selectStyle.top = `${editTop}px`;
                selectStyle.left = `${editLeft}px`;
                selectStyle.margin = '0px';
            }
    
            //获取当前单元格
            getEditedCell() {
                const { wtOverlays } = this.hot.view.wt;
                const editorSection = this.checkEditorSection();
                let editedCell;
    
                switch (editorSection) {
                    case 'top':
                        editedCell = wtOverlays.topOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 101;
                        break;
                    case 'corner':
                        editedCell = wtOverlays.topLeftCornerOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 103;
                        break;
                    case 'left':
                        editedCell = wtOverlays.leftOverlay.clone.wtTable.getCell({
                            row: this.row,
                            col: this.col
                        });
                        this.select.style.zIndex = 102;
                        break;
                    default:
                        editedCell = this.hot.getCell(this.row, this.col);
                        this.select.style.zIndex = '';
                        break;
                }
    
                return editedCell < 0 ? void 0 : editedCell;
            }
    
            focus() {
                this.select.focus();
            }
    
            close() {
                this._opened = false;
                this.select.style.display = 'none';
            }
    
            //读取选项配置到编辑器
            prepare(row, col, prop, td, originalValue, cellProperties) {
                // Remember to invoke parent's method
                super.prepare(row, col, prop, td, originalValue, cellProperties);
                const selectOptions = this.cellProperties.selectOptions;
                let options;
    
                if (typeof selectOptions === 'function') {
                    options = this.prepareOptions(selectOptions(this.row, this.col, this.prop));
                } else {
                    options = this.prepareOptions(selectOptions);
                }
    
                Handsontable.dom.empty(this.select);
    
                Handsontable.helper.objectEach(options, (value, key) => {
                    const optionElement = this.hot.rootDocument.createElement('div');
    
                    const checkbox = this.hot.rootDocument.createElement('input');
                    checkbox.type = "checkbox";
                    optionElement.appendChild(checkbox);
    
                    var textSpan = this.hot.rootDocument.createElement('span');
                    textSpan.innerHTML = value;
                    optionElement.appendChild(textSpan);
    
                    optionElement.value = key;
    
                    Handsontable.dom.addClass(optionElement, 'MultiSelectOption');
    
                    //Handsontable.dom.fastInnerHTML(optionElement, value);
                    this.select.appendChild(optionElement);
                });
            }
            prepareOptions(optionsToPrepare) {
                let preparedOptions = {};
    
                if (Array.isArray(optionsToPrepare)) {
                    for (let i = 0, len = optionsToPrepare.length; i < len; i++) {
                        preparedOptions[optionsToPrepare[i]] = optionsToPrepare[i];
                    }
    
                } else if (typeof optionsToPrepare === 'object') {
                    preparedOptions = optionsToPrepare;
                }
    
                return preparedOptions;
            }
    
        }
    
    
        // Put editor in dedicated namespace
        //将编辑器添加到专用命名空间
        Handsontable.editors.MultiSelectEditor = MultiSelectEditor;
        // Register alias
        //编辑器注册别名
        Handsontable.editors.registerEditor('MultiSelect', MultiSelectEditor);
    
    })(Handsontable);
    MutiSelect.js

    2.MutiSelect.css

    .htMultiSelectEditor {
        /*
      * This hack enables to change <select> dimensions in WebKit browsers
      */
        -webkit-appearance: menulist-button !important;
        position: absolute;
         auto;
        height:100px;
        z-index:9999;
        background-color:white;
        border:1px solid gray;
    }
    .MultiSelectOption:hover{
        background-color:antiquewhite;
    }
    MultiSelect.css
  • 相关阅读:
    Python笔记_第四篇_高阶编程_再议装饰器和再议内置函数
    Python笔记_第四篇_高阶编程_实例化方法、静态方法、类方法和属性方法概念的解析。
    Python笔记_第四篇_高阶编程_二次封装
    Python笔记_第四篇_高阶编程_反射_(getattr,setattr,deattr,hasattr)
    Python笔记_第四篇_高阶编程_正则表达式_3.正则表达式深入
    Python笔记_第四篇_高阶编程_正则表达式_2.正则表达式入门
    Python笔记_第四篇_高阶编程_正则表达式_1.正则表达式简介(re模块)
    Python笔记_第四篇_高阶编程_检测_2.文档检测
    愿你的眼中总有光芒,活成你想要的模样!
    ruby-rails 环境搭建
  • 原文地址:https://www.cnblogs.com/ggtc/p/15584200.html
Copyright © 2011-2022 走看看