第一步,给表格添加事件
export var finalCollsArr = null // 用来存放单元格的id数组
let flag = false// 当鼠标被按下时,为true,放开是为true
let indexs = []// 用来存放鼠标经过的单元格在整个表格的位置,鼠标按下时被初始化,
table.addEventListener('mousedown', (e) => {
getTbList(table) // 获取表格的单元格id
if (e.button == 0) {
flag = true
indexs = []
}
}, false)
tableNode.addEventListener('mousemove', (e) => {
if (flag) { // 只有鼠标被按下时,才会执行复合代码
search(e.target, indexs)
}
}, false)
tableNode.addEventListener('mouseup', () => {
flag = false
finalCollsArr = collsDistribute(indexs)
}, false)
第二步:获取单元格在表格中id分布,获取鼠标选中的单元格id分布
// 整个单元格的id分布,在删除行列,插入行列中有使用到
export var list = new Array()
/**
* 获取单元格id
* @param {表格节点} curTable
*/
export const getTbList = (curTable) => {
if (!curTable) {
return
}
const rowLength = curTable.rows.length
const colLength = getCellLength(curTable)
// let arr = new Array(colLength).fill('undefined');
// list = new Array(rowLength).fill(arr);
list = new Array()
for (let i = 0; i < rowLength; i++) {
let arr = []
for (let j = 0; j < colLength; j++) {
arr.push('undefined')
}
list.push(arr)
}
let rowNum = 0;
let colNum = 0
for (let i = 0; i < rowLength; i++) {
for (let j = 0; j < colLength; j++) {
// 获取单元格
let tdNode = curTable.rows[rowNum].cells[colNum]
if (!tdNode) {
continue
}
for (let k = j; k < colLength; k++) {
if (list[i][k] != 'undefined' ) {
continue
}
list[i][k] = tdNode.getAttribute('id')
j = k;
break
}
let rowspan = tdNode.rowSpan
let colspan = tdNode.colSpan
if (rowspan>1 && colspan>1) {
for (let k = 0; k < rowspan; k++) {
for (let z = 0; z < colspan; z++) {
list[i+k][j+z] = tdNode.getAttribute('id')
}
}
}else if(rowspan>1 || colspan>1){
for (let k = 0; k < rowspan; k++) {
list[i+k][j] = tdNode.getAttribute('id')
}
for (let k = 0; k < colspan; k++) {
list[i][j+k] = tdNode.getAttribute('id')
}
}
colNum++;
}
rowNum++;
colNum = 0;
}
console.log("list: ", list);
// 第一行 id
oneRowId = list[0];
let newArray = list[0].map(function (col, i) {
return list.map(function (row) {
return row[i]
})
})
// 第一列 id
oneColId = newArray[0]
}
/**
* 将鼠标经过的单元格添加到数组
* @param {单元格} tdNode
* @param {数组} indexs
* @returns
*/
export const search = (tdNode, indexs) => {
if (tdNode.getAttribute('tagname') != 'entry') {
return
}
let id = tdNode.getAttribute('id')
let ind = indexs.indexOf(id)
if (ind == -1) {
// 不存在
indexs.push(id)
} else if (ind != -1 && ind != indexs.length - 1) {
indexs.splice(ind, 1)
}
}
/**
* 获取鼠标选中的单元格分布
* @param {数组} indexs
*/
export const collsDistribute = (indexs) => {
let collsArr = new Array()
let firstId = indexs[0]
let endId = indexs[indexs.length-1]
let arrRow = new Array();
let arrCol = new Array();
// 获取id在list数组的第几行第几列
let row = 0
let col = 0
for (let i = 0; i < list.length; i++) {
list[i].forEach((id,index)=>{
if(id === firstId){
arrRow[row++] = i
arrCol[col++] = index
}
});
list[i].forEach((id,index)=>{
if(id === endId){
arrRow[row++] = i
arrCol[col++] = index
}
});
}
arrRow.sort()
arrCol.sort()
let minCols = Math.min(arrCol[0], arrCol[arrCol.length-1])
let maxCols = Math.max(arrCol[0], arrCol[arrCol.length-1])
let minRows = Math.min(arrRow[0], arrRow[arrRow.length-1])
let maxRows = Math.max(arrRow[0], arrRow[arrRow.length-1])
let x = maxRows-minRows+1
let y = maxCols-minCols+1
for (let i = 0; i < x; i++) {
let arr = []
for (let j = 0; j < y; j++) {
arr.push('false')
}
collsArr.push(arr)
}
// let arr = new Array(y).fill('false')
// let collsArr = new Array(x).fill(arr)
for (let i = 0; i < x; i++) {
console.log("minRows: " + minRows);
for (let j = 0; j < y; j++) {
console.log("minCols: " + minCols);
collsArr[i][j] = list[minRows][minCols++]
if (minCols>maxCols) {
break
}
}
minCols = maxCols + 1 - y
minRows++
if (minRows>maxRows) {
break
}
}
// console.log("===================");
// console.log(collsArr);
return collsArr;
}
/**
* 获取表格的列数
* @param {表格节点} curTable
* @returns
*/
export const getCellLength = (curTable) => {
let rowNode = curTable.rows[0]
let tdNodeList = rowNode.getElementsByTagName('td')
let length = 0
for (let i = 0; i < tdNodeList.length; i++) {
let rowspan = tdNodeList[i].getAttribute('colspan')
if (rowspan) {
length += Number(rowspan)
} else {
length++
}
}
return length
}
/**
* 获取单元格所在的列数
* @param {单元格} td
* @param {列数组} arr
*/
export const getCellsTrain = (td, arr) => {
let id = td.getAttribute('id')
// 列位置
let col = -1
for (let i = 0; i < arr.length; i++) {
if(arr[i].indexOf(id) != -1){
col = i
break
}
}
return col
}
第三步:合并单元格
/**
* 合并单元格
* @param {单元格id数组,第一步中的finalCollsArr} arr
*/
export const mergeCells = (arr) => {
// 获取行列值最小的单元格
let id = arr[0][0]
let td = document.getElementById(id)
// 行和列
let colspan = arr[0].length
let rowspan = arr.length
td.setAttribute('colspan', colspan)
td.setAttribute('rowspan', rowspan)
for (let i = 0; i < rowspan; i++) {
for (let j = 0; j <colspan; j++) {
// 相同的id跳过
if (arr[i][j] == id) {
continue
}
let delColls = document.getElementById(arr[i][j])
// 不存在的单元格跳过
if (!delColls) {
continue
}
// 删除单元格
delColls.parentNode.removeChild(delColls)
}
}
}
第四步:插入行
/**
* 插入行
* @param {单元格} colls
* @param {表格} curTable
* @param {true:向上插入, false:向下插入} isUp
*/
export const addRow = (colls, curTable, isUp) => {
// 获取单元格所在行数
let row = colls.parentNode.rowIndex; // 行位置
let rowNode = colls.parentNode // 行节点
// 获取总列数
let cellLength = getCellLength(curTable)
let arrId = list[row]
// 判断上(下)一行有没有这一行的元素
// 在第一行上方插入和在最后一行下方插入就不用判断
if (!((isUp && row == 0) || (!isUp && row == list.length-1))) {
let arr = isUp ? list[row-1] : list[row+1]
let redoArr = []
for (let i = 0; i < arrId.length; i++) {
if (arrId[i] == arr[i]) {
cellLength--
if (redoArr.indexOf(arrId[i]) == -1) {
redoArr.push(arrId[i])
}
}
}
for (let i = 0; i < redoArr.length; i++) {
let td = document.getElementById(redoArr[i])
let rowspan = td.rowSpan
td.rowSpan = rowspan + 1
}
}
const trNode = document.createElement('tr')
trNode.setAttribute("tagname", "row"); // 设置属性
trNode.setAttribute("id", `tag_${global.id}`);
global.id = global.id + 1
let tdHtml = ''
for (let j = 0; j < cellLength; j++) {
tdHtml += `<td tagname='entry' id='tag_${global.id}' style="padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);"> </td>`
global.id = global.id + 1
}
trNode.innerHTML = tdHtml
if (isUp) {
rowNode.parentNode.insertBefore(trNode, rowNode)
}else{
rowNode.parentNode.insertBefore(trNode, rowNode.nextSibling)
}
}
第五步:插入列
/**
* 插入列
* @param {单元格} colls
* @param {true:向左插入, false:向右插入} isLeft
* @returns
*/
export const addCell = (colls, isLeft) => {
// const rowLength = curTable.rows.length // 行數量
// 行转列
let newArray = list[0].map(function (col, i) {
return list.map(function (row) {
return row[i]
})
})
// 获取单元格所在的列
let col = getCellsTrain(colls, newArray)
if (col == -1) {
return
}
// 这一列的id
let arrId = newArray[col]
let arr = []
if (!((isLeft && col == 0) || (!isLeft && col == newArray.length-1))) {
arr = isLeft ? newArray[col-1] : newArray[col+1]
}
let redoArr = []
for (let i = 0; i < arrId.length; i++) {
let td = document.getElementById(arrId[i])
// 创建单元格节点
let newCell = document.createElement('td')
newCell.setAttribute("tagname", "entry")
newCell.setAttribute("id", `tag_${global.id}`)
global.id = global.id + 1
newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
newCell.innerHTML = ' '
if (arr.length>0) {
if (arr[i] == arrId[i]) {
if (redoArr.indexOf(arrId[i]) == -1) {
let colspan = td.colSpan
td.colSpan = colspan + 1
redoArr.push(arrId[i])
}
continue
}
let tdBro = document.getElementById(arr[i])
if (Array.from(new Set(arrId)).length < arrId.length) {
if (td.parentNode.rowIndex != tdBro.parentNode.rowIndex) {
if (isLeft) {
td = tdBro.nextSibling
}else{
td = tdBro.previousSibling
}
}
}
}else {
if (td.parentNode.rowIndex != i) {
if (col == 0) {
td = document.getElementById(newArray[col + 1][i])
td.parentNode.insertBefore(newCell, td)
} else {
td = document.getElementById(newArray[col - 1][i])
td.parentNode.appendChild(newCell)
}
continue
}
}
if (isLeft) {
!td ? curTable.rows[i].appendChild(newCell) : td.parentNode.insertBefore(newCell, td)
} else {
td.parentNode.insertBefore(newCell, td.nextSibling)
}
}
}
第六步:删除行
// colls: 单元格节点, curTable:表格节点
export const delRow = (colls, curTable) => {
const rowLength = curTable.rows.length // 行數量
if (rowLength < 2) {
alert('不能全部删除!')
return
}
let row = colls.parentNode.rowIndex; // 行位置
// let col = colls.cellIndex; // 列位置
let rowNode = colls.parentNode // 行节点
let tdNodeList = rowNode.getElementsByTagName('td')
// 遍历这一行的单元格有没有跨行的, 如果跨行就将下一行的这一列的单元格跨行-1,相同跨列
for (let i = 0; i < tdNodeList.length; i++) {
let rowspan = tdNodeList[i].rowSpan
if (rowspan>1) {
let colspan = tdNodeList[i].colSpan
let rowChild = curTable.rows[row+1]
let colChild = rowChild.cells[i]
let newCell = document.createElement('td')
newCell.setAttribute("tagname", "entry")
newCell.setAttribute("id", `tag_${global.id}`)
global.id = global.id + 1
newCell.setAttribute("rowspan", rowspan-1)
newCell.setAttribute("colspan", colspan)
newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
newCell.innerHTML = ' '
rowChild.insertBefore(newCell, colChild)
}
}
// 遍历有没有被跨行的,将被跨行的跨行数-1
let arrId = list[row]
for (let i = 0; i < arrId.length; i++) {
let td = document.getElementById(arrId[i])
let tdRow = td.parentNode.rowIndex;
if (row == tdRow) {
continue
}
let rowNum = td.rowSpan
td.rowSpan = rowNum -1
}
rowNode.parentNode.removeChild(rowNode)
}
第七步:删除列
// colls: 单元格节点, curTable:表格节点
export const delCell = (colls, curTable) => {
const cellLength = getCellLength(curTable)
if (cellLength < 2) {
alert('不能全部删除!')
return
}
// 行转列
let newArray = list[0].map(function (col, i) {
return list.map(function (row) {
return row[i]
})
})
let col = getCellsTrain(colls, newArray)
if (col == -1) {
return
}
// 这一列的值
let arrId = newArray[col]
for (let i = 0; i < arrId.length; i++) {
let td = document.getElementById(arrId[i])
let tdCol = getCellsTrain(td, newArray)
// 判断单元格有没有被跨列,有,将跨列的 跨列-1
if (tdCol != col) {
let colNum = td.colSpan
td.colSpan = colNum -1
continue
}
// 判断单元格有没有跨列,有跨列,在该单元格的后面添加一个单元格 跨列-1
let colspan = td.colSpan
if (colspan>1) {
let tdNext = td.nextSibling
let rowspan = td.rowSpan
let newCell = document.createElement('td')
newCell.setAttribute("tagname", "entry")
newCell.setAttribute("id", `tag_${global.id}`)
global.id = global.id + 1
newCell.setAttribute("rowspan", rowspan)
newCell.setAttribute("colspan", colspan-1)
newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
newCell.innerHTML = ' '
td.parentNode.insertBefore(newCell, tdNext)
}
td.parentNode.removeChild(td)
}
}