UNPKG

@smallpot/demo01

Version:

``` npm install table-layout ```

1,254 lines (1,067 loc) 34.1 kB
import {deepmerge} from "./tool.js" class TableLayout { constructor(el,opts={}) { this.el=el;//当前表格dom对象 this.opts=deepmerge(this.defaultOpts(),opts); this.tableArr=[];//表格以二维数组的形式存储[[单元格dom,单元格dom],[单元格dom,单元格dom]...] this.tableJson={};//表格以键值的形式存储eg: {1-1:单元格dom,1-2:单元格dom,...} this.selectArr=[];//已选中的单元格 this.selectedJson={ isSelecting:false,//是否开始选择单元格 rowMin:null,//选中单元格的最小行编号 rowMax:null,//选中单元格的最大行编号 cellMin:null,//选中单元格的最小列编号 cellMax:null,//选中单元格的最大列编号 mousedownTd:null, mousemoveTd:null, mouseupTd:null, }; this.dragJson={ isStartDrag:false,//是否开始拖拽 isDragX:false,//横向是否在被拖拽 isDragY:false,//纵向是否在被拖拽 dragEl:null,//被拖拽的单元格 oldX:null,//拖拽前的坐标 oldY:null,//拖拽后的坐标 colItem:null,//当前被拖拽单元格对应的colgroup rowItem:null,//当前被拖拽的行 colItemWidth:null,//当前被拖拽单元格对应的colgroup的初始宽度 rowItemHeight:null//当前被拖拽的行的初始高度 }; this.selectAreaStyle={ width:"", height:"", boxSizing:"border-box", backgroundColor:"rgba(0, 0, 0, 0.1)", border:"2px solid rgb(31, 187, 125)", position: "absolute", left:"", top:"", pointerEvents:"none", } } active(){ if(!this.el){ return false; } this.createSelectArea(); this.init(); this.delegate(this.el, 'click','td', (e,el)=> { this.multipleChoice(e,el) }); this.delegate(this.el, 'mousedown','td', (e,el)=> { this.startSelection(e,el); this.startDrag(e,el) }); this.delegate(this.el, 'mousemove','td', (e,el)=> { this.selecting(e,el); this.readyDrag(e,el); this.dragging(e,el); }); this.delegate(document, 'mouseup','td', (e,el)=> { this.endSelection(e,el); this.endDrag(e,el) }); this.el.addEventListener('mousedown',()=>{ this.setSelectArea() }) this.el.addEventListener('mousemove',()=>{ this.setSelectArea() }) } //多选 multipleChoice(e,el){ if(e.shiftKey){ if(this.selectArr.length>0){ this.addSelected([...this.selectArr,el]) }else{ this.addSelected([this.selectedJson["mousedownTd"],this.selectedJson["mousemoveTd"],el]); } } } //开始选择 startSelection(e,el){ if(this.dragJson['isDragX']||this.dragJson['isDragY']){ return false; } if(!this.selectedJson["isSelecting"]&&!e.shiftKey){ this.cancelAllSelected(); this.selectedJson["mousemoveTd"]=null; this.selectedJson["mouseupTd"]=null; this.selectedJson["isSelecting"]=true; this.selectedJson["mousedownTd"]=el; this.addSelected([this.selectedJson["mousedownTd"]]); } } //正在选择 selecting(e,el){ if(this.selectedJson["isSelecting"]&&!e.shiftKey){ if(!this.selectedJson["mousemoveTd"]){ this.selectedJson["mousemoveTd"]=el; }else{ let num1= this.selectedJson["mousemoveTd"].getAttribute("td_num"); let num2= el.getAttribute("td_num"); if(num1!=num2){ this.selectedJson["mousemoveTd"]=el; this.cancelAllSelected(); this.addSelected([this.selectedJson["mousedownTd"],this.selectedJson["mousemoveTd"]]); } } } } //结束选择 endSelection(e){ if(this.selectedJson["isSelecting"]&&!e.shiftKey){ this.selectedJson["isSelecting"]=false; } } //准备拖拽(用于判断是否可拖拽) readyDrag(e,el){ if(this.selectedJson["isSelecting"]){ return false; } let boundingClientRect=el.getBoundingClientRect(); let tdRight=boundingClientRect['x']+el.offsetWidth; let tdBottom=boundingClientRect['y']+el.offsetHeight; if((this.opts['xDrag']&&!this.dragJson['isDragY']&&tdRight-e.clientX<=8)|| (this.opts['xDrag']&&this.dragJson['isStartDrag']&&this.dragJson['isDragX'])){ el.style.cursor="col-resize"; this.dragJson['isDragX']=true; }else if((this.opts['yDrag']&&!this.dragJson['isDragX']&&tdBottom-e.clientY<=8)|| (this.opts['yDrag']&&this.dragJson['isStartDrag']&&this.dragJson['isDragY'])){ el.style.cursor="row-resize"; this.dragJson['isDragY']=true; }else{ el.style.cursor="context-menu"; this.dragJson['isDragX']=false; this.dragJson['isDragY']=false; } } //开始拖拽 startDrag(e,el){ if(this.dragJson['isDragX']){ let colgroup =this.el.querySelector('colgroup') let cols=[...colgroup.childNodes].filter(item=>{ return item.nodeName.toUpperCase()=="COL"; }); this.dragJson['isStartDrag']=true this.dragJson['oldX'] = e.clientX; this.dragJson['oldY'] = e.clientY; this.dragJson['dragEl']=el; let td_num_obj=null; if(this.dragJson['dragEl'].colSpan > 1){ td_num_obj=this.getRowCellNum(this.dragJson['dragEl'],"end_td"); }else{ td_num_obj=this.getRowCellNum(this.dragJson['dragEl'],"td_num"); } let n=td_num_obj['col']; this.dragJson['colItem']=cols[n] this.dragJson['colItemWidth']=Number(this.dragJson['colItem'].width); this.dragJson['colItem'].setAttribute("move",true); }else if(this.dragJson['isDragY']){ this.dragJson['isStartDrag']=true this.dragJson['oldX'] = e.clientX; this.dragJson['oldY'] = e.clientY; this.dragJson['dragEl']=el; this.dragJson['rowItem']=el.parentElement; this.dragJson['rowItemHeight']=Number(this.dragJson['rowItem'].getAttribute("height")); this.dragJson['rowItem'].setAttribute("move",true); } } //正在拖拽 dragging(e){ if(!this.dragJson['isStartDrag']){ return; } if(this.dragJson['colItem']){ let move= this.dragJson['colItem'].getAttribute("move"); if(move){ let w=this.dragJson['colItemWidth']+(e.clientX - this.dragJson['oldX']); let newColItemWidth=w>=this.opts['columnWidth']?w:this.opts['columnWidth']; this.dragJson['colItem'].width=newColItemWidth } }else if(this.dragJson['rowItem']){ let move= this.dragJson['rowItem'].getAttribute("move"); if(move){ let h=this.dragJson['rowItemHeight']+(e.clientY - this.dragJson['oldY']); let newRowHeight=h>=this.opts['rowHeight']?h:this.opts['rowHeight'] this.dragJson['rowItem'].setAttribute("height",newRowHeight); } } } //结束拖拽 endDrag(){ this.dragJson['colItem']&&this.dragJson['colItem'].removeAttribute("move"); this.dragJson['rowItem']&&this.dragJson['rowItem'].removeAttribute("move"); this.dragJson={ isStartDrag:false, isDragX:false, isDragY:false, dragEl:null, oldX:null, oldY:null, colItem:null, rowItem:null, colItemWidth:null, rowItemHeight:null } } init(){ this.setSelectAreaSizeAndPosition(0,0,0,0); let table= this.initTable(this.el); let tbody=this.el.querySelector('tbody'); this.initTbody(tbody); let rows=[...table.rows]; this.tableArr = Array.from({length: rows.length}, () =>[]); let row_repeat={}; let rowMaxLen=rows[0];//单元格最多的行 rows.forEach((trItem,trIndex)=>{ let tr_item=this.initTr(trItem); let cells = [...tr_item.cells]; if(rowMaxLen){ let oldCells=[...rowMaxLen.cells]; if(cells.length>oldCells.length){ rowMaxLen=tr_item; } } cells.forEach((tdItem)=>{ let td_item=this.initTd(tdItem); if(td_item.colSpan > 1){ for(let c=1;c<td_item.colSpan;c++){ this.tableArr[trIndex].push(td_item); } } if(td_item.rowSpan > 1){ for(let r=1;r<td_item.rowSpan;r++){ let row_num=trIndex+r; for(let c=0;c<td_item.colSpan;c++){ if(!row_repeat[row_num]){ row_repeat[row_num]=[] } row_repeat[row_num].push(td_item); } } } this.tableArr[trIndex].push(td_item); }) }) this.createColgroup(rowMaxLen,(res)=>{ let tableWidth=0; let cols=[...res.childNodes].filter(item=>{ return item.nodeName.toUpperCase()=="COL" }); cols.forEach(item=>{ tableWidth+=Number(item.width); }) this.el.width=tableWidth; }); //重新排序 for (let tr_index in row_repeat) { let cells=row_repeat[tr_index]; this.tableArr[tr_index].push(...cells) this.tableArr[tr_index].sort((a,b)=>a.offsetLeft-b.offsetLeft); } this.setSign(); this.cancelAllSelected(); } //跨行跨列的单元格设置起止标记 setSign(){ let table_arr=this.tableArr&&this.tableArr.length>0?this.tableArr:[]; let table_json={}; table_arr.forEach((tr_item,tr_index)=>{ tr_item.forEach((td_item,td_index)=>{ table_json[`${tr_index}-${td_index}`]=td_item; let td_num= td_item.getAttribute("td_num"); if(!td_num){ td_item.setAttribute("td_num",`${tr_index}-${td_index}`); } if(td_item.colSpan > 1||td_item.rowSpan > 1){ let start_td= td_item.getAttribute("start_td"); let end_td= td_item.getAttribute("end_td"); if(!start_td){ td_item.setAttribute("start_td",`${tr_index}-${td_index}`); } if(!end_td){ td_item.setAttribute("end_td",`${tr_index+td_item.rowSpan-1}-${td_index+td_item.colSpan-1}`); } } }) }) this.tableJson=table_json; } //事件代理 delegate(element, eventType, selector, fn){ element.addEventListener(eventType, evt => { let e=evt || window.event e.preventDefault(); let el = e.target while (el.matches&&!el.matches(selector)) { if (element === el) { el = null break } el = el.parentNode } el && fn.call(el, e, el) }) return element } //选中单元格 addSelected(tdArr){ if(tdArr&&tdArr.length>0){ this.selectArr=[]; let td_limit=this.getCellNumLimit(tdArr); const fn=(table_json,rowMin,rowMax,cellMin,cellMax)=>{ for (let key in table_json) { let td_item=table_json[key]; let arr=key.split("-"); let item_num_arr=[Number(arr[0]),Number(arr[1])] if((item_num_arr[0]>=rowMin&&item_num_arr[0]<=rowMax)&& (item_num_arr[1]>=cellMin&&item_num_arr[1]<=cellMax)) { td_item.setAttribute("selected",true); this.selectArr.push(td_item) } } let td_limit_next=this.getCellNumLimit(this.selectArr); let w=td_limit_next["cell_max"]-td_limit_next["cell_min"]+1; let h=td_limit_next["row_max"]-td_limit_next["row_min"]+1; this.selectedJson["rowMin"]=td_limit_next['row_min']; this.selectedJson["rowMax"]=td_limit_next['row_max']; this.selectedJson["cellMin"]=td_limit_next['cell_min']; this.selectedJson["cellMax"]=td_limit_next['cell_max']; if(w*h!==this.selectArr.length){ this.selectArr=[]; fn(this.tableJson,td_limit_next['row_min'],td_limit_next['row_max'],td_limit_next['cell_min'],td_limit_next['cell_max']); } } fn(this.tableJson,td_limit['row_min'],td_limit['row_max'],td_limit['cell_min'],td_limit['cell_max']); } } //取消选中单元格 cancelAllSelected(){ this.selectedJson["rowMin"]=null; this.selectedJson["rowMax"]=null; this.selectedJson["cellMin"]=null; this.selectedJson["cellMax"]=null; this.selectArr=[]; this.setSelectAreaSizeAndPosition(0,0,0,0); if(this.tableArr&&this.tableArr.length>0){ this.tableArr.forEach((tr_item)=>{ tr_item.forEach((td_item)=>{ td_item.removeAttribute("selected"); }) }) } } getRowCellNum(el,type){ if(!el||!type){ return {}; } let type_str=el.getAttribute(type); if(type_str){ let arr=type_str.split("-"); return { row:Number(arr[0]), col:Number(arr[1]) } } return {} } getCellNumLimit(cellArr=[]){ const getMaxAndMinFn=(arr)=>{ let newArr=arr.filter(n => n!=null); newArr.sort((a,b)=>a-b); return{ min:newArr[0], max:newArr[newArr.length-1] } } let row_arr=[]; let col_arr=[]; let cellArrFilter=cellArr.filter(n => n!=null); cellArrFilter.forEach((td_item)=>{ let td_num_obj=this.getRowCellNum(td_item,"td_num"); row_arr.push(td_num_obj['row']); col_arr.push(td_num_obj['col']) if(td_item.rowSpan > 1||td_item.colSpan > 1){ let start_td_obj=this.getRowCellNum(td_item,"start_td"); let end_td_obj=this.getRowCellNum(td_item,"end_td"); row_arr.push(start_td_obj['row']); col_arr.push(start_td_obj['col']); row_arr.push(end_td_obj['row']); col_arr.push(end_td_obj['col']) } }) let rowLimit=getMaxAndMinFn(row_arr); let cellLimit=getMaxAndMinFn(col_arr); let row_min=rowLimit['min']; let row_max=rowLimit['max']; let cell_min=cellLimit['min']; let cell_max=cellLimit['max']; return { row_min, row_max, cell_min, cell_max } } //合并单元格 mergeTdFn(){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let key=`${this.selectedJson["rowMin"]}-${this.selectedJson["cellMin"]}`; let parentNode = this.tableJson[key].parentElement; let fragmentTd=document.createDocumentFragment(); let fragmentTdChildren=document.createDocumentFragment(); this.selectArr.forEach((item)=>{ let td_num= item.getAttribute("td_num"); let arr=[...item.childNodes]; arr.forEach((itemChildNode)=>{ fragmentTdChildren.appendChild(itemChildNode); }) if(td_num!==key){ fragmentTd.appendChild(item); } }) let newTd = this.tableJson[key].cloneNode(true); newTd.rowSpan=(this.selectedJson["rowMax"]-this.selectedJson["rowMin"])+1; newTd.colSpan=(this.selectedJson["cellMax"]-this.selectedJson["cellMin"])+1; newTd.appendChild(fragmentTdChildren); parentNode&&parentNode.replaceChild(newTd,this.tableJson[key]); fragmentTd=null; this.init(); } //拆解单元格 disassemblyFn(){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let map=new Map();//要拆解的单元格 this.selectArr.forEach((item)=>{ if(item.rowSpan>1||item.colSpan>1){ if(map.has(item)){ let nub=map.get(item)+1; map.set(item,nub); }else{ map.set(item,1); } } }) this.tableArr.forEach((rowItem,RIndex)=>{ rowItem.forEach((tdItem,CIndex)=>{ if(map.has(tdItem)){ let tdNumObj=this.getRowCellNum(tdItem,"td_num"); if(tdNumObj["row"]==RIndex&&tdNumObj["col"]==CIndex){ tdItem.rowSpan=1; tdItem.colSpan=1; }else{ let newTd = this.createTd(); rowItem.splice(CIndex,1,newTd); } } }) }) let newTbody=this.tableArrToDom(this.tableArr); let tbody=this.el.querySelector('tbody') this.el.replaceChild(newTbody,tbody); this.init(); } //删除整列 delEntireColumn(){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let colgroup =this.el.querySelector('colgroup') let fragment=document.createDocumentFragment(); let tempJson={}; let map=new Map(); let cols=[...colgroup.childNodes].filter(item=>{ return item.nodeName.toUpperCase()=="COL" }); cols.forEach((item,index)=>{ if(index>=this.selectedJson["cellMin"]&&index<=this.selectedJson["cellMax"]){ fragment.appendChild(item); } }) for (let key in this.tableJson) { let td_item=this.tableJson[key]; let arr=key.split("-"); let itemKey={ row:Number(arr[0]), col:Number(arr[1]) } if(itemKey['col']>=this.selectedJson["cellMin"]&&itemKey['col']<=this.selectedJson["cellMax"]){ if(td_item.colSpan>1){ if(map.has(td_item)){ let nub=map.get(td_item)+1; map.set(td_item,nub); }else{ map.set(td_item,1); } let td_num=td_item.getAttribute("td_num"); tempJson[td_num]=td_item; }else{ fragment.appendChild(td_item); } } } for (let key in tempJson) { let td_item=tempJson[key]; let nub=parseInt(map.get(td_item)/td_item.rowSpan); if(td_item.colSpan-nub>0){ td_item.colSpan=td_item.colSpan-nub; td_item.removeAttribute("start_td"); td_item.removeAttribute("end_td"); }else{ fragment.appendChild(td_item); } } map=null; tempJson=null; fragment=null; this.init(); } //table_arr转dom树 tableArrToDom(tableArr){ let fragment=document.createDocumentFragment(); let newTbody = document.createElement('tbody'); let tbody=this.el.querySelector('tbody'); if(tbody){ newTbody=tbody.cloneNode(); } tableArr.forEach((rowItem,RIndex)=>{ if(rowItem.length>0){//rowItem.length等于0表示要删除的行 let newTr = this.createTr(); let oldTr=rowItem[0].parentNode; let height=this.opts['rowHeight']; if(oldTr){ newTr = oldTr.cloneNode(); height=oldTr.getAttribute("height")||this.opts['rowHeight']; } newTr.setAttribute("height",height); rowItem.forEach((tdItem)=>{ let tdNumObj=this.getRowCellNum(tdItem,"td_num"); if(tdNumObj["row"]==RIndex){ newTr.appendChild(tdItem); }else if(!tdNumObj["row"]&&tdNumObj["row"]!=0){ newTr.appendChild(tdItem); } }) fragment.appendChild(newTr); } }) newTbody.appendChild(fragment); return newTbody; } //删除整行 delEntireRow(){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let map=new Map(); let newArr=this.tableArr.map((rowItem,RIndex)=>{ if(RIndex>=this.selectedJson["rowMin"]&&RIndex<=this.selectedJson["rowMax"]){ rowItem.forEach((tdItem)=>{ if(tdItem.rowSpan>1){//跨行的单元格收集起来,特殊处理 if(map.has(tdItem)){ let nub=map.get(tdItem)+1;//记录单元格占有数 map.set(tdItem,nub); }else{ map.set(tdItem,1); } } }) return []; }else{ return rowItem; } }) map.forEach((num,tdItem)=>{ console.log(num); let nub=parseInt(map.get(tdItem)/tdItem.colSpan); if(tdItem.rowSpan-nub>0){ tdItem.rowSpan=tdItem.rowSpan-nub; } let start_td_obj=this.getRowCellNum(tdItem,"start_td"); let end_td_obj=this.getRowCellNum(tdItem,"end_td"); let td_num_obj=this.getRowCellNum(tdItem,"td_num"); for(let r=start_td_obj["row"];r<=end_td_obj["row"];r++){ if(r>=this.selectedJson["rowMin"]&&r<=this.selectedJson["rowMax"]){ continue; } tdItem.setAttribute("td_num",`${r}-${td_num_obj['col']}`); break; } }); let newTbody=this.tableArrToDom(newArr); let tbody=this.el.querySelector('tbody') this.el.replaceChild(newTbody,tbody); this.init(); } //右侧插入列 insertColumnAfter(number=1){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let tempJson={}; // let table=this.el; // let rows=[...table.rows]; let colgroup =this.el.querySelector('colgroup') let cols=[...colgroup.childNodes].filter(item=>{ return item.nodeName.toUpperCase()=="COL" }); cols.forEach((item,index)=>{ if(index===this.selectedJson["cellMax"]){ let fragment=document.createDocumentFragment(); for(let i=0;i<number;i++){ let newCol = document.createElement('col'); newCol.width=this.opts["columnWidth"]; fragment.appendChild(newCol); } this.insertAfter(fragment,item) } }) for (let key in this.tableJson) { let td_item=this.tableJson[key]; let arr=key.split("-"); let itemKey={ row:Number(arr[0]), col:Number(arr[1]) } if(itemKey['col']==this.selectedJson["cellMax"]){ if(td_item.colSpan>1||td_item.rowSpan>1){ let td_num=td_item.getAttribute("td_num"); tempJson[td_num]=td_item; }else{ let fragment=document.createDocumentFragment(); for(let i=0;i<number;i++){ let newTd = this.createTd(); fragment.appendChild(newTd); } this.insertAfter(fragment,td_item) } } } let newTrJson={} for (let key in tempJson) { let td_item=tempJson[key]; let start_td_obj=this.getRowCellNum(td_item,"start_td"); let end_td_obj=this.getRowCellNum(td_item,"end_td"); if(end_td_obj["col"]===this.selectedJson["cellMax"]){ for(let r=start_td_obj["row"];r<=end_td_obj["row"];r++){ newTrJson[r]=[]; this.tableArr[r].forEach((td,index)=>{ newTrJson[r].push(td) if(index===end_td_obj["col"]){ for(let i=0;i<number;i++){ let newTd = this.createTd(); newTrJson[r].push(newTd); } } }) } }else{ td_item.colSpan=td_item.colSpan+number; } } this.updateTrFn(newTrJson); this.init(); } //左侧插入列 insertColumnBefore(number=1){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let colgroup =this.el.querySelector('colgroup') let tempJson={}; let cols=[...colgroup.childNodes].filter(item=>{ return item.nodeName.toUpperCase()=="COL" }); cols.forEach((item,index)=>{ if(index===this.selectedJson["cellMax"]){ let fragment=document.createDocumentFragment(); for(let i=0;i<number;i++){ let newCol = document.createElement('col'); newCol.width=this.opts["columnWidth"];// fragment.appendChild(newCol); } colgroup.insertBefore(fragment,item); } }) for (let key in this.tableJson) { let td_item=this.tableJson[key]; let parent = td_item.parentNode; let arr=key.split("-"); let itemKey={ row:Number(arr[0]), col:Number(arr[1]) } if(itemKey['col']==this.selectedJson["cellMin"]){ if(td_item.colSpan>1||td_item.rowSpan>1){ let td_num=td_item.getAttribute("td_num"); tempJson[td_num]=td_item; }else{ let fragment=document.createDocumentFragment(); for(let i=0;i<number;i++){ let newTd = this.createTd(); fragment.appendChild(newTd); } parent.insertBefore(fragment,td_item); } } } let newTrJson={} for (let key in tempJson) { let td_item=tempJson[key]; let start_td_obj=this.getRowCellNum(td_item,"start_td"); let end_td_obj=this.getRowCellNum(td_item,"end_td"); if(start_td_obj["col"]===this.selectedJson["cellMin"]){ for(let r=start_td_obj["row"];r<=end_td_obj["row"];r++){ newTrJson[r]=[]; this.tableArr[r].forEach((td,index)=>{ if(index===start_td_obj["col"]){ for(let i=0;i<number;i++){ let newTd = this.createTd(); newTrJson[r].push(newTd); } } newTrJson[r].push(td) }) } }else{ td_item.colSpan=td_item.colSpan+number; } } this.updateTrFn(newTrJson); this.init(); } //在后方插入行 insertRowBehind(number=1){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let tempJson={}; let table=this.el; let rows=[...table.rows]; let fragment=document.createDocumentFragment(); let newTr = this.createTr(); newTr.setAttribute("height",this.opts['rowHeight']); for (let key in this.tableJson) { let td_item=this.tableJson[key]; let arr=key.split("-"); let itemKey={ row:Number(arr[0]), col:Number(arr[1]) } if(itemKey['row']==this.selectedJson["rowMax"]){ if(td_item.rowSpan>1){ let td_num=td_item.getAttribute("td_num"); tempJson[td_num]=td_item; }else{ let newTd = this.createTd(); newTr.appendChild(newTd); } } } for (let key in tempJson) { let td_item=tempJson[key]; let end_td_obj=this.getRowCellNum(td_item,"end_td"); if(end_td_obj['row']===this.selectedJson["rowMax"]){ for(let i=0;i<td_item.colSpan;i++){ let newTd = this.createTd(); newTr.appendChild(newTd); } }else{ td_item.rowSpan=td_item.rowSpan+number; } } for(let i=0;i<number;i++){ let tr=newTr.cloneNode(true); fragment.appendChild(tr); } this.insertAfter(fragment,rows[this.selectedJson["rowMax"]]) this.init(); } //在前方插入行 insertRowAhead(number=1){ if(this.selectArr&&this.selectArr.length===0){ alert("没有选中的单元格") return false; } let tempJson={}; let table=this.el; let rows=[...table.rows]; let fragment=document.createDocumentFragment(); let newTr = this.createTr(); newTr.setAttribute("height",this.opts['rowHeight']); for (let key in this.tableJson) { let td_item=this.tableJson[key]; let arr=key.split("-"); let itemKey={ row:Number(arr[0]), col:Number(arr[1]) } if(itemKey['row']==this.selectedJson["rowMin"]){ if(td_item.rowSpan>1){ let td_num=td_item.getAttribute("td_num"); tempJson[td_num]=td_item; }else{ let newTd = this.createTd(); newTr.appendChild(newTd); } } } for (let key in tempJson) { let td_item=tempJson[key]; let start_td_obj=this.getRowCellNum(td_item,"start_td"); if(start_td_obj['row']===this.selectedJson["rowMin"]){ for(let i=0;i<td_item.colSpan;i++){ let newTd = this.createTd(); newTr.appendChild(newTd); } }else{ td_item.rowSpan=td_item.rowSpan+number; } } for(let i=0;i<number;i++){ let tr=newTr.cloneNode(true); fragment.appendChild(tr); } let parent = rows[this.selectedJson["rowMin"]].parentNode; parent.insertBefore(fragment,rows[this.selectedJson["rowMin"]]); this.init(); } insertAfter(newElement,targetElement){ //获取目标元素的父节点 let parent = targetElement.parentNode; if(parent.lastChild == targetElement&&parent.appendChid){ parent.appendChid(newElement); }else{ //nextSibling是表示下一个兄弟元素节点 parent.insertBefore(newElement,targetElement.nextSibling); } } // updateTrFn(trJson){ let rows=[...this.el.rows]; let obj={} for (let key in trJson) { let parentNode = rows[key].parentNode; let trArr=trJson[key]; let fragment=document.createDocumentFragment(); let newTr = this.createTr(); newTr.setAttribute("height",this.opts['rowHeight']); trArr.forEach(td=>{ let td_num=td.getAttribute("td_num"); let td_num_obj=this.getRowCellNum(td,"td_num"); //obj:标记td_num,用于去重 //td_num_obj['row']==key: 只有属于当前行的单元格才能添加到新创建的行 if (td_num&&!obj[td_num]&&td_num_obj['row']==key) { newTr.appendChild(td); obj[td_num] = true; }else if(!td_num){//如果不存在td_num就是新添加的单元格,直接添加到新创建的行 newTr.appendChild(td); } }) fragment.appendChild(newTr); parentNode&&parentNode.replaceChild(fragment,rows[key]); } } //创建选择区域 createSelectArea(){ if(!this.el){ return false; } let div=document.createElement("div"); div.className="selectArea"; for (let name in this.selectAreaStyle) { div.style[name]=this.selectAreaStyle[name]; } this.el.appendChild(div); } //设置选择区域位置及宽高 setSelectArea(){ let {top,left,width,height}=this.computeSelectAreaPosition(this.selectedJson["rowMin"],this.selectedJson["cellMin"],this.selectedJson["rowMax"],this.selectedJson["cellMax"]); this.setSelectAreaSizeAndPosition(width,height,left,top); } //设置选择区域样式 setSelectAreaSizeAndPosition(width,height,left,top){ let selectArea=document.querySelector(".selectArea"); if(!selectArea){ return; } selectArea.style.width=`${width}px`; selectArea.style.height=`${height}px`; selectArea.style.left=`${left}px`; selectArea.style.top=`${top}px`; } //计算选择区域位置及宽高 computeSelectAreaPosition(row_min,cell_min,row_max,cell_max){ if(row_min!=null&&cell_min!=null&&row_max!=null&&cell_max!=null){ let startTd=this.tableJson[`${row_min}-${cell_min}`]; let endTd=this.tableJson[`${row_max}-${cell_max}`]; let top=startTd.offsetTop; let left=startTd.offsetLeft; let width=(endTd.offsetLeft+endTd.offsetWidth)-left; let height=(endTd.offsetTop+endTd.offsetHeight)-top; return { top, left, width, height } } return { top:0, left:0, width:0, height:0 } } createColgroup(row,cb){ if(!row){ return } let colgroup =this.el.querySelector('colgroup') if(!colgroup){ let colgroup = document.createElement('colgroup'); colgroup.setAttribute('id',"colgroup"); let cells = [...row.cells]; cells.forEach((td_item)=>{ let width=this.opts["columnWidth"]?this.opts["columnWidth"]:td_item.offsetWidth; let col = document.createElement('col'); col.width=width; colgroup.appendChild(col); }) this.el.appendChild(colgroup); cb(colgroup); } if(colgroup&&cb){ colgroup.setAttribute('id',"colgroup"); cb(colgroup); } } //设置opts setOpts(opts){ this.opts=deepmerge(this.opts,opts); } //默认配置 defaultOpts(){ return { xDrag:true,//是否开启横向拖拽 yDrag:true,//是否开启纵向拖拽 rowHeight:32,//行高 columnWidth:100,//列宽 tableProps:{ className:[], style:{}, attr:{} }, tbodyProps:{ className:[], style:{}, attr:{} }, trProps:{ className:[], style:{}, attr:{} }, tdProps:{ className:[], style:{}, attr:{} } } } //dom对象基本初始化 baseInit(obj,propsStr){ let props=this.opts[propsStr]?this.opts[propsStr]:{}; let classNameArr=props["className"]?props["className"]:[]; let styleProps=props["style"]?props["style"]:{}; let attr=props["attr"]?props["attr"]:{}; classNameArr.forEach(className=>{ obj.classList.add(className); }) for (let prop in styleProps) { let styleVal=styleProps[prop]; obj.style[prop]=styleVal; } for (let name in attr) { let attrVal=attr[name]; obj.setAttribute(name,attrVal); } return obj; } //初始化表格 initTable(table){ let tbody=table.querySelector('tbody'); if(!tbody){ let tbodyEl = document.createElement('tbody'); let rows=[...table.rows]; rows.forEach(tr=>{ tbodyEl.appendChild(tr); }) table.appendChild(tbodyEl); } let dom=this.baseInit(table,"tableProps"); return dom; } //初始化Tbody initTbody(tbody){ let dom=this.baseInit(tbody,"tbodyProps"); return dom; } //初始化行 initTr(tr){ let height=tr.getAttribute("height"); if(!height){ tr.setAttribute("height",this.opts["rowHeight"]); } let dom=this.baseInit(tr,"trProps"); return dom; } //初始化单元格 initTd(td){ td.removeAttribute("td_num"); td.removeAttribute("start_td"); td.removeAttribute("end_td"); let newTd=this.baseInit(td,"tdProps"); return newTd; } //创建行 createTr(){ let newTr =document.createElement('tr'); return newTr; } //创建单元格 createTd(){ let newTd = document.createElement('td'); return newTd; } //获取选中单元格 getSelectArr(){ return this.selectArr; } //设置选择区域样式 setSelectAreaStyle(opts={}){ let selectArea=document.querySelector(".selectArea"); if(!selectArea){ return; } this.selectAreaStyle=Object.assign({},this.selectAreaStyle,opts); for (let name in this.selectAreaStyle) { selectArea.style[name]=this.selectAreaStyle[name]; } } } export default TableLayout