luckysheet移动端添加复制粘贴(批量粘贴)操作按钮

需求:

        移动端的luckysheet需要有类似钉钉写作文档中的选中一块区域后弹出复制、剪切等按钮。

 操作:

        luckysheet滑动选中一块区域后会在左上角和右下角有小圆点,点击小圆点或者滑动选择区域时弹出操作框(类似钉钉文档)

开工:

添加dom

CTRL+P找到Moblie.js文件,在document的touchend回调的末尾加上自己的函数,开始处理。

 ShowMobileOperation函数内容如下:

    function ShowMobileOperation(event){
        // nby 第一步、判断触摸完毕是否显示复制块
        if(event.target.contains($('.luckysheet-cs-touchhandle-btn')[1]) && $("#mobileOperation").length==0){
            // nby 移动端操作区域dom
            if(Store.isMobile){//这个是Store.isMobile是在全局新加的变量,用以表示是移动端,因为luckysheet本身判断有问题,只能手动填写
                $("body").append(`
                <div id='mobileOperation' style="z-index:10000;position: absolute;width: auto;height: auto;user-select:none;">
                    <div style="display: flex; ">
                        <div style="background-color:wheat;display: flex;justify-content:space-between;align-item:center;padding: 6px;width:auto;border-radius: 10px;">
				            <div id='mobileCopyBtn' style="display: flex;cursor: pointer;margin-right: 10px;"><svg style="width:18px;height:18px;" t="1673399639231" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1908" width="200" height="200"><path d="M720 192h-544A80.096 80.096 0 0 0 96 272v608C96 924.128 131.904 960 176 960h544c44.128 0 80-35.872 80-80v-608C800 227.904 764.128 192 720 192z m16 688c0 8.8-7.2 16-16 16h-544a16 16 0 0 1-16-16v-608a16 16 0 0 1 16-16h544a16 16 0 0 1 16 16v608z" p-id="1909"></path><path d="M848 64h-544a32 32 0 0 0 0 64h544a16 16 0 0 1 16 16v608a32 32 0 1 0 64 0v-608C928 99.904 892.128 64 848 64z" p-id="1910"></path><path d="M608 360H288a32 32 0 0 0 0 64h320a32 32 0 1 0 0-64zM608 520H288a32 32 0 1 0 0 64h320a32 32 0 1 0 0-64zM480 678.656H288a32 32 0 1 0 0 64h192a32 32 0 1 0 0-64z" p-id="1911"></path></svg>
                                <span style='font-size: 14px;white-space: nowrap;'>全复制</span>
                            </div>
				            <div id='mobilePasteBtn' style="display: flex;border: none;cursor: pointer;margin-right: 6px;"><svg style="width:18px;height:18px;" t="1673399835334" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2894" width="200" height="200"><path d="M901.117698 948.224208V814.080577H959.997536v134.143631h-58.879838z m0-328.959095H959.997536v133.887632h-58.879838v-133.887632z m0-198.655454H959.997536v133.887632h-58.879838v-133.887632z m0-207.359429H959.997536v134.143631h-58.879838V213.25023z m-153.599578 752.125931h120.319669V1024h-120.319669v-58.623839z m43.238281-162.303553a93.490943 93.490943 0 0 1-94.23334 92.671745H279.833006v78.079785h-58.879838v-78.079785H158.284541a93.490943 93.490943 0 0 1-94.233341-92.671745V306.689973L355.096799 0.002816H696.57426a93.490943 93.490943 0 0 1 94.233341 92.671745v26.879926H865.277796v58.623839h-74.572594v624.894282zM162.27813 306.177974h203.289041V91.906563z m557.259267-213.503413a22.630338 22.630338 0 0 0-23.039936-22.015939H436.837375v245.247325a61.260632 61.260632 0 0 1-61.439831 60.927833H135.142204v426.238828a22.476738 22.476738 0 0 0 23.039937 22.015939H696.57426a22.451138 22.451138 0 0 0 23.039937-22.015939V92.674561zM450.558937 1024h-120.319669v-58.623839h120.319669V1024z m212.479416 0h-120.319669v-58.623839h120.319669V1024z" fill="#333333" p-id="2895"></path></svg>
                                <span style='font-size: 14px;white-space: nowrap;'>粘贴</span>
                            </div>
                            <div id='copyShowVal' style="display: flex;cursor: pointer;margin-right: 2px;"><svg style="width:20px;height:20px;" t="1675401312010" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1855" width="200" height="200"><path d="M725.333333 341.333333h128v512H341.333333v-128H213.333333V213.333333h512v128z m0 42.666667v341.333333H384v85.333334h426.666667V384h-85.333334zM256 256v426.666667h426.666667V256H256z" fill="#444444" p-id="1856"></path></svg>
                                <span style='font-size: 14px;white-space: nowrap;'>复制文本</span>
                            </div>
		                </div>
                    </div>
                </div>`);
                let col = luckysheet_touchmove_startPos.x
                let row = luckysheet_touchmove_startPos.y
                // let col = Store.touchCoord.x+'px'
                // let row = Store.touchCoord.y+'px'
                $("#mobileOperation").css({"left": col, "top": row});   //定位操作区域,这几个变量上面有计算
                // nby 第二步,对具体的按钮进行处理
                // 监听复制文本的按钮,就是只复制单元格的文本,不包括批注、背景等
                $('#copyShowVal').on('touchend',function(event){

                    // $("#luckysheet-copy-array2").click()
                    // 先得到cell中的m字段二维数组
                    // let copyData=luckysheet.getRangeValue()
                    // copyData = copyData.map(arrItem=>arrItem.map(cell=>cell?.m))
                    // let htmlData='' //构建html数据
                    // let tr_Str = copyData.reduce((preVal,cur)=>{
                    //     let str=''
                    //     cur.forEach((strItem)=>{
                    //         str += `<td>${strItem}</td>`
                    //     })
                    //     return preVal+`<tr>${str}</tr>`
                    // },'')
                    // htmlData = `<table>${tr_Str}</table>`

                    // selection.copybyformat(event,htmlData)
                    // 上面是之前的代码,本想用html标签的形式作为复制的内容,发现不行,但是在键盘操作cv是行的。

                    let copyData=luckysheet.getRangeValue()
                    // 生成luckysheet的二维数组copyData,因为只复制文本值,所以取单元格对象的m字段
                    // {fa: 'General', t: 'n'}
                    copyData=copyData.map((arrCell)=>arrCell.map(cell=>({v:cell?.m,m:cell?.m,ct:{fa: 'General', t: 'n'}}))) 
                    selection.copybyformat(event,JSON.stringify(copyData))
                    Store.isCopyText = true //判定是点击的仅复制文本还是全复制按钮

                    event.stopPropagation();
                    event.stopImmediatePropagation()
                    setTimeout(()=>{
                        $('#mobileOperation').remove()
                    },200)//这里可以封装为一个函数,下面经常用。
                })

                // 监听粘贴
                $('#mobilePasteBtn').on('touchend',function(event){
                    // nby  以下会对粘贴做一些限制,直接从luckysheet本身的粘贴按钮复制过来
                    if (isEditMode() || Store.allowEdit === false) {//此模式下禁用粘贴
                        return;
                    }
                    if ($(event.target).hasClass("formulaInputFocus")) {
                        return;
                    }
                    if (Store.luckysheet_select_save.length > 1) {
                        if (isEditMode()) {
                            alert(locale_drag.noPaste);
                        }
                        else {
                            tooltip.info(locale_drag.noPaste, "");
                        }
                        return;
                    }
                    selection.isPasteAction = true;
                    selection.paste(event,'btn',Store.isCopyText)   // nby Store.isCopyText全局变量用来
                    luckysheetactiveCell();
                   
                    event.stopPropagation();
                    event.stopImmediatePropagation()

                    setTimeout(()=>{
                        $('#mobileOperation').remove()
                    },200)
                })

                //   监听全复制按钮
                $('#mobileCopyBtn').on('touchend',function(event){
                    //复制时存在格式刷状态,取消格式刷
                    if (menuButton.luckysheetPaintModelOn) {
                        menuButton.cancelPaintModel();
                    }

                    if (Store.luckysheet_select_save.length == 0) {
                        return;
                    }

                    //复制范围内包含部分合并单元格,提示
                    if (Store.config["merge"] != null) {
                        let has_PartMC = false;

                        for (let s = 0; s < Store.luckysheet_select_save.length; s++) {
                            let r1 = Store.luckysheet_select_save[s].row[0],
                                r2 = Store.luckysheet_select_save[s].row[1];
                            let c1 = Store.luckysheet_select_save[s].column[0],
                                c2 = Store.luckysheet_select_save[s].column[1];

                            has_PartMC = hasPartMC(Store.config, r1, r2, c1, c2);

                            if (has_PartMC) {
                                break;
                            }
                        }

                        if (has_PartMC) {
                            if (isEditMode()) {
                                alert(locale_drag.noMerge);
                            }
                            else {
                                tooltip.info(locale_drag.noMerge, "");
                            }
                            return;
                        }
                    }

                    //多重选区 有条件格式时 提示
                    let cdformat = Store.luckysheetfile[getSheetIndex(Store.currentSheetIndex)].luckysheet_conditionformat_save;
                    if (Store.luckysheet_select_save.length > 1 && cdformat != null && cdformat.length > 0) {
                        let hasCF = false;

                        let cf_compute = conditionformat.getComputeMap();

                        label:
                        for (let s = 0; s < Store.luckysheet_select_save.length; s++) {
                            if (hasCF) {
                                break;
                            }

                            let r1 = Store.luckysheet_select_save[s].row[0],
                                r2 = Store.luckysheet_select_save[s].row[1];
                            let c1 = Store.luckysheet_select_save[s].column[0],
                                c2 = Store.luckysheet_select_save[s].column[1];

                            for (let r = r1; r <= r2; r++) {
                                for (let c = c1; c <= c2; c++) {
                                    if (conditionformat.checksCF(r, c, cf_compute) != null) {
                                        hasCF = true;
                                        continue label;
                                    }
                                }
                            }
                        }

                        if (hasCF) {
                            if (isEditMode()) {
                                alert(locale_drag.noMulti);
                            }
                            else {
                                tooltip.info(locale_drag.noMulti, "");
                            }
                            return;
                        }
                    }

                    //多重选区 行不一样且列不一样时 提示
                    if (Store.luckysheet_select_save.length > 1) {
                        let isSameRow = true,
                            str_r = Store.luckysheet_select_save[0].row[0],
                            end_r = Store.luckysheet_select_save[0].row[1];
                        let isSameCol = true,
                            str_c = Store.luckysheet_select_save[0].column[0],
                            end_c = Store.luckysheet_select_save[0].column[1];

                        for (let s = 1; s < Store.luckysheet_select_save.length; s++) {
                            if (Store.luckysheet_select_save[s].row[0] != str_r || Store.luckysheet_select_save[s].row[1] != end_r) {
                                isSameRow = false;
                            }
                            if (Store.luckysheet_select_save[s].column[0] != str_c || Store.luckysheet_select_save[s].column[1] != end_c) {
                                isSameCol = false;
                            }
                        }

                        if ((!isSameRow && !isSameCol) || selectIsOverlap()) {
                            if (isEditMode()) {
                                alert(locale_drag.noMulti);
                            }
                            else {
                                tooltip.info(locale_drag.noMulti, "");
                            }
                            return;
                        }
                    }
                    // nby 全复制也需要做数据自适应
                    // selection.copy(event);
                    selection.copybyformat(event,JSON.stringify(luckysheet.getRangeValue()))

                    // Store.isCopyText = false//这是全复制,故需要将复制文本关闭
                    Store.isCopyText = true; //这是全复制,故需要将复制文本关闭
                    Store.luckysheet_paste_iscut = false;
                    luckysheetactiveCell();

                    event.stopPropagation();
                    event.stopImmediatePropagation()
                    
                    setTimeout(()=>{
                        $('#mobileOperation').remove()
                    },200)
                    
                })
            }
        }
        
   
    }

 上面函数的简易思路:

  1. 触摸完毕,创建dom,挂载到body上,之后定位到触摸坐标。
  2. 为dom中的几个按钮添加点击事件处理。

各按钮回调思路

  • 文本复制按钮(#copyShowVal)回调。

        (1)首先用luckysheet.getRangeValue()获取复制区域的单元格对象数据(返回结果是二维数组),然后构建出需要的符合单元格对象格式的二维数组。(就是把m也赋值给v,其他批注啥的都不要,这样去粘贴构建出来的数据就都是显示值m了)

        (2)之后将构建好的数据交给selection.copybyformat(event,JSON.stringify(copyData))去处理。 最后隐藏操作区域。

  • 全复制(#mobileCopyBtn)按钮回调

        同上

  • 粘贴(#mobilePasteBtn)按钮回调

        (1)调用selection.paste(event,'btn',Store.isCopyText)  方法,由于需要做批量粘贴,还需要对粘贴的数据进行处理。

        (2)进入paste后,获取textarea的内容data(实现复制粘贴功能时clipboard不支持就用这种方法),之后交给pasteHandler方法,在pasteHandler方法里对数据进行自适应处理。自适应数据处理函数代码如下:

   // nby 实现批量粘贴数据的函数
        function selfAdaptionData(data){
            let primData = $.extend(true, [], data);
            // 判断当前选区,实现批量粘贴
            let range = luckysheet.getRange()//获取需要粘贴的区域
            let pasteRange = [range[0].row[1] - range[0].row[0] + 1 , range[0].column[1] - range[0].column[0] + 1 ]

            let copyRange = [data.length,data[0].length]

            let residueColumnNum = pasteRange[1] - copyRange[1]  //粘贴区域的列数是否比已复制的数据列数多
            let residueRowNum = pasteRange[0] - copyRange[0]

            if(residueColumnNum > 0 || residueRowNum > 0){
                // 粘贴区域更大,扩大粘贴的数据
                // 先扩大列数
                let columnCount = parseInt(pasteRange[1]/copyRange[1])
                for(let i = 1 ; i < columnCount ; i++){
                    data = data.map((arr,index)=>{
                        return [...arr,...primData[index]]

                        //这里新添加的每行数据需要用对应的那一行,并且需要是之前的数据
                    })
                }
                // 扩大行数
                let primDataArr = $.extend(true, [], data);//先存下,一次粘贴的数据
                let rowCount = parseInt(pasteRange[0]/copyRange[0])
                for(let i = 1 ; i < rowCount ; i++){
                    data = [...data,...primDataArr]
                }
            }
            return data
        }

selfAdaptionData函数说明:

        通过luckysheet.getRange()获取粘贴的区域,计算出粘贴区域的行数和列数pasteRange,又通过入参data计算出拷贝区域的行列数copyRange,通过行列相减,判断粘贴区域是否大于拷贝区域。

        如果大于,则需要扩大数据。计算出最小整数倍,然后循环添加。先把列处理好之后就是行。

补充说明:

我这里的批量粘贴是啥?

        比如我复制一个格子,在需要粘贴之前又框选4x4的格子,如果支持批量粘贴就共有4x4=16个格子都有数据,不然只有第一个格子才有粘贴的数据。

        

最后附上效果图:

由于移动端操作的局限性,后续还需要加上其他功能按钮 。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值