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

需求:

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

 操作:

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

开工:

添加dom

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

luckysheet移动端添加复制粘贴(批量粘贴)操作按钮_第1张图片

 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(`
                
全复制
粘贴
复制文本
`); 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 += `${strItem}` // }) // return preVal+`${str}` // },'') // htmlData = `${tr_Str}
` // 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个格子都有数据,不然只有第一个格子才有粘贴的数据。

        

luckysheet移动端添加复制粘贴(批量粘贴)操作按钮_第2张图片

最后附上效果图:

luckysheet移动端添加复制粘贴(批量粘贴)操作按钮_第3张图片

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

你可能感兴趣的:(luckysheet,前端)