基于element-ui表格批量选中复制表格内容工具

371 阅读2分钟

背景

业务系统中表格数据通常以导出excel文件的方式批量下载到本地,面对一些只需要其中一列或几列部分数据的场景通常存在数据冗余且操作不够简便的问题,因此在特定业务中存在直接批量复制部分表格内容到剪切板的需求。

使用方法

基本用法是先将mixin导入组件, 调用clipInit方法将element-ui表格ref值作为参数传入,初始化会创建右键复制自定义组件、ctrl+c按键监听、取消默认复制行为

        clipInit (clipContent) {
            if (!(window.Node && clipContent instanceof Node)) return;
            this.clipContent = clipContent;
            this.$nextTick(() => {
                document.onselectstart = function (event) {
                    event.returnValue = false;
                };
            });
            const Profile = Vue.extend(menus);
            // 创建 Profile 实例,并挂载到一个元素上。
            this.instance = new Profile({
                propsData: {
                    sty: {
                        left: '0px',
                        top: '0px'
                    },
                    copyCode: this.copyCode,
                    isShow: false}
            }).$mount();
            document.body.appendChild(this.instance.$el);
            document.addEventListener('keydown', this.doCopy);
            this.$once('hook:beforeDestroy', () => {
                document.removeEventListener('keydown', this.doCopy);
            });
        },
        doCopy (e) {
            if (e.keyCode === 67 && (navigator.platform.match('Mac') ? e.metaKey : e.ctrlKey)){
                e.preventDefault();
                this.copyCode();
            }
        },

再对表格绑定mousedown事件,鼠标在表格按下时会清除选中并对鼠标滑过表格区域的td添加背景色

clickDown ($event) {
            let rangeStartX, rangeSEndX, rangeStartY, rangeEndY;
            this.instance._props.isShow = false;
            const startX = $event.pageX;
            const startY = $event.pageY;
            Array.from(this.clipContent.querySelectorAll('td.checkClips')).map((ov) => {
                ov.classList.remove('checkClips');
            });
            let $el = $event.target
            while($el && ($el.nodeName !== 'TD' || $el.nodeName !== 'TABLE')){
                if($el.nodeName === 'TD') {
                    $el.classList.add('checkClips');
                    $el = undefined
                } else {
                    $el = $el.parentNode
                }
            }
            const td = Array.from(this.clipContent.querySelectorAll('td'));
            this.clipContent.onmousemove = ($event) => {
                [rangeStartX, rangeSEndX] = [startX, $event.pageX].sort((a, b) => { return a - b; });
                [rangeStartY, rangeEndY] = [startY, $event.pageY].sort((a, b) => { return a - b; });
                td.map(v => {
                    const tdItemL = v.getBoundingClientRect().left + window.pageXOffset;
                    const tdItemR = v.getBoundingClientRect().right + window.pageXOffset;
                    const tdItemT = v.getBoundingClientRect().top + window.pageYOffset;
                    const tdItemB = v.getBoundingClientRect().bottom + window.pageYOffset;
                    const isinnerX = (rangeStartX < tdItemL && tdItemL < rangeSEndX) || (rangeStartX < tdItemR && tdItemR < rangeSEndX); // td左右边X轴坐标是否在滑动起始点X轴坐标内
                    const isinnerY = (rangeStartY < tdItemT && tdItemT < rangeEndY) || (rangeStartY < tdItemB && tdItemB < rangeEndY);// td上下边Y轴坐标是否在滑动起始点Y轴坐标内
                    const level = (tdItemL < rangeStartX && rangeStartX < tdItemR) || (tdItemL < rangeSEndX && rangeSEndX < tdItemR); // 滑动起始点X轴坐标是否在td左右边X轴坐标内
                    const vertical = (tdItemT < rangeStartY && rangeStartY < tdItemB) || (tdItemT < rangeEndY && rangeEndY < tdItemB); // 滑动起始点Y轴坐标是否在td上下边Y轴坐标内
                    if ((isinnerX && isinnerY) || (vertical && isinnerX) || (level && isinnerY) || (level && vertical)) {
                        v.classList.add('checkClips');
                    } else {
                        v.classList.remove('checkClips');
                    }
                });
            };
        },

ctrl+c复制或右键菜单复制会将选中表格td内容做字符串拼接并复制到剪切板上

copyCode () {
            const text = Array.from(this.clipContent.querySelectorAll('.checkClips'))
                .reduce((Str, v) => {
                    Str += v.innerText + '\n';
                    return Str;
                }, '');
            if (!text) {
                this.instance._props.isShow = false;
                return;
            }
            this.$copyText(text).then(
                (res) => {
                    this.$message.success('复制成功');
                    this.instance._props.isShow = false;
                    Array.from(this.clipContent.querySelectorAll('.checkClips'))
                        .map((v) => {
                            v.classList.remove('checkClips');
                        });
                },
                (e) => {
                    this.$message.error('复制失败');
                }
            );
        },

github地址 github.com/zake-github…