当前位置:   article > 正文

js 自定义表格的合并单元格、插入行列、删除行列_js合并单元格

js合并单元格

第一步,给表格添加事件

  1. export var finalCollsArr = null // 用来存放单元格的id数组
  2. let flag = false// 当鼠标被按下时,为true,放开是为true
  3. let indexs = []// 用来存放鼠标经过的单元格在整个表格的位置,鼠标按下时被初始化,
  4. table.addEventListener('mousedown', (e) => {
  5. getTbList(table) // 获取表格的单元格id
  6. if (e.button == 0) {
  7. flag = true
  8. indexs = []
  9. }
  10. }, false)
  11. tableNode.addEventListener('mousemove', (e) => {
  12. if (flag) { // 只有鼠标被按下时,才会执行复合代码
  13. search(e.target, indexs)
  14. }
  15. }, false)
  16. tableNode.addEventListener('mouseup', () => {
  17. flag = false
  18. finalCollsArr = collsDistribute(indexs)
  19. }, false)

第二步:获取单元格在表格中id分布,获取鼠标选中的单元格id分布

  1. // 整个单元格的id分布,在删除行列,插入行列中有使用到
  2. export var list = new Array()
  3. /**
  4. * 获取单元格id
  5. * @param {表格节点} curTable
  6. */
  7. export const getTbList = (curTable) => {
  8. if (!curTable) {
  9. return
  10. }
  11. const rowLength = curTable.rows.length
  12. const colLength = getCellLength(curTable)
  13. // let arr = new Array(colLength).fill('undefined');
  14. // list = new Array(rowLength).fill(arr);
  15. list = new Array()
  16. for (let i = 0; i < rowLength; i++) {
  17. let arr = []
  18. for (let j = 0; j < colLength; j++) {
  19. arr.push('undefined')
  20. }
  21. list.push(arr)
  22. }
  23. let rowNum = 0;
  24. let colNum = 0
  25. for (let i = 0; i < rowLength; i++) {
  26. for (let j = 0; j < colLength; j++) {
  27. // 获取单元格
  28. let tdNode = curTable.rows[rowNum].cells[colNum]
  29. if (!tdNode) {
  30. continue
  31. }
  32. for (let k = j; k < colLength; k++) {
  33. if (list[i][k] != 'undefined' ) {
  34. continue
  35. }
  36. list[i][k] = tdNode.getAttribute('id')
  37. j = k;
  38. break
  39. }
  40. let rowspan = tdNode.rowSpan
  41. let colspan = tdNode.colSpan
  42. if (rowspan>1 && colspan>1) {
  43. for (let k = 0; k < rowspan; k++) {
  44. for (let z = 0; z < colspan; z++) {
  45. list[i+k][j+z] = tdNode.getAttribute('id')
  46. }
  47. }
  48. }else if(rowspan>1 || colspan>1){
  49. for (let k = 0; k < rowspan; k++) {
  50. list[i+k][j] = tdNode.getAttribute('id')
  51. }
  52. for (let k = 0; k < colspan; k++) {
  53. list[i][j+k] = tdNode.getAttribute('id')
  54. }
  55. }
  56. colNum++;
  57. }
  58. rowNum++;
  59. colNum = 0;
  60. }
  61. console.log("list: ", list);
  62. // 第一行 id
  63. oneRowId = list[0];
  64. let newArray = list[0].map(function (col, i) {
  65. return list.map(function (row) {
  66. return row[i]
  67. })
  68. })
  69. // 第一列 id
  70. oneColId = newArray[0]
  71. }
  72. /**
  73. * 将鼠标经过的单元格添加到数组
  74. * @param {单元格} tdNode
  75. * @param {数组} indexs
  76. * @returns
  77. */
  78. export const search = (tdNode, indexs) => {
  79. if (tdNode.getAttribute('tagname') != 'entry') {
  80. return
  81. }
  82. let id = tdNode.getAttribute('id')
  83. let ind = indexs.indexOf(id)
  84. if (ind == -1) {
  85. // 不存在
  86. indexs.push(id)
  87. } else if (ind != -1 && ind != indexs.length - 1) {
  88. indexs.splice(ind, 1)
  89. }
  90. }
  91. /**
  92. * 获取鼠标选中的单元格分布
  93. * @param {数组} indexs
  94. */
  95. export const collsDistribute = (indexs) => {
  96. let collsArr = new Array()
  97. let firstId = indexs[0]
  98. let endId = indexs[indexs.length-1]
  99. let arrRow = new Array();
  100. let arrCol = new Array();
  101. // 获取id在list数组的第几行第几列
  102. let row = 0
  103. let col = 0
  104. for (let i = 0; i < list.length; i++) {
  105. list[i].forEach((id,index)=>{
  106. if(id === firstId){
  107. arrRow[row++] = i
  108. arrCol[col++] = index
  109. }
  110. });
  111. list[i].forEach((id,index)=>{
  112. if(id === endId){
  113. arrRow[row++] = i
  114. arrCol[col++] = index
  115. }
  116. });
  117. }
  118. arrRow.sort()
  119. arrCol.sort()
  120. let minCols = Math.min(arrCol[0], arrCol[arrCol.length-1])
  121. let maxCols = Math.max(arrCol[0], arrCol[arrCol.length-1])
  122. let minRows = Math.min(arrRow[0], arrRow[arrRow.length-1])
  123. let maxRows = Math.max(arrRow[0], arrRow[arrRow.length-1])
  124. let x = maxRows-minRows+1
  125. let y = maxCols-minCols+1
  126. for (let i = 0; i < x; i++) {
  127. let arr = []
  128. for (let j = 0; j < y; j++) {
  129. arr.push('false')
  130. }
  131. collsArr.push(arr)
  132. }
  133. // let arr = new Array(y).fill('false')
  134. // let collsArr = new Array(x).fill(arr)
  135. for (let i = 0; i < x; i++) {
  136. console.log("minRows: " + minRows);
  137. for (let j = 0; j < y; j++) {
  138. console.log("minCols: " + minCols);
  139. collsArr[i][j] = list[minRows][minCols++]
  140. if (minCols>maxCols) {
  141. break
  142. }
  143. }
  144. minCols = maxCols + 1 - y
  145. minRows++
  146. if (minRows>maxRows) {
  147. break
  148. }
  149. }
  150. // console.log("===================");
  151. // console.log(collsArr);
  152. return collsArr;
  153. }
  154. /**
  155. * 获取表格的列数
  156. * @param {表格节点} curTable
  157. * @returns
  158. */
  159. export const getCellLength = (curTable) => {
  160. let rowNode = curTable.rows[0]
  161. let tdNodeList = rowNode.getElementsByTagName('td')
  162. let length = 0
  163. for (let i = 0; i < tdNodeList.length; i++) {
  164. let rowspan = tdNodeList[i].getAttribute('colspan')
  165. if (rowspan) {
  166. length += Number(rowspan)
  167. } else {
  168. length++
  169. }
  170. }
  171. return length
  172. }
  173. /**
  174. * 获取单元格所在的列数
  175. * @param {单元格} td
  176. * @param {列数组} arr
  177. */
  178. export const getCellsTrain = (td, arr) => {
  179. let id = td.getAttribute('id')
  180. // 列位置
  181. let col = -1
  182. for (let i = 0; i < arr.length; i++) {
  183. if(arr[i].indexOf(id) != -1){
  184. col = i
  185. break
  186. }
  187. }
  188. return col
  189. }

第三步:合并单元格

  1. /**
  2. * 合并单元格
  3. * @param {单元格id数组,第一步中的finalCollsArr} arr
  4. */
  5. export const mergeCells = (arr) => {
  6. // 获取行列值最小的单元格
  7. let id = arr[0][0]
  8. let td = document.getElementById(id)
  9. // 行和列
  10. let colspan = arr[0].length
  11. let rowspan = arr.length
  12. td.setAttribute('colspan', colspan)
  13. td.setAttribute('rowspan', rowspan)
  14. for (let i = 0; i < rowspan; i++) {
  15. for (let j = 0; j <colspan; j++) {
  16. // 相同的id跳过
  17. if (arr[i][j] == id) {
  18. continue
  19. }
  20. let delColls = document.getElementById(arr[i][j])
  21. // 不存在的单元格跳过
  22. if (!delColls) {
  23. continue
  24. }
  25. // 删除单元格
  26. delColls.parentNode.removeChild(delColls)
  27. }
  28. }
  29. }

第四步:插入行

  1. /**
  2. * 插入行
  3. * @param {单元格} colls
  4. * @param {表格} curTable
  5. * @param {true:向上插入, false:向下插入} isUp
  6. */
  7. export const addRow = (colls, curTable, isUp) => {
  8. // 获取单元格所在行数
  9. let row = colls.parentNode.rowIndex; // 行位置
  10. let rowNode = colls.parentNode // 行节点
  11. // 获取总列数
  12. let cellLength = getCellLength(curTable)
  13. let arrId = list[row]
  14. // 判断上(下)一行有没有这一行的元素
  15. // 在第一行上方插入和在最后一行下方插入就不用判断
  16. if (!((isUp && row == 0) || (!isUp && row == list.length-1))) {
  17. let arr = isUp ? list[row-1] : list[row+1]
  18. let redoArr = []
  19. for (let i = 0; i < arrId.length; i++) {
  20. if (arrId[i] == arr[i]) {
  21. cellLength--
  22. if (redoArr.indexOf(arrId[i]) == -1) {
  23. redoArr.push(arrId[i])
  24. }
  25. }
  26. }
  27. for (let i = 0; i < redoArr.length; i++) {
  28. let td = document.getElementById(redoArr[i])
  29. let rowspan = td.rowSpan
  30. td.rowSpan = rowspan + 1
  31. }
  32. }
  33. const trNode = document.createElement('tr')
  34. trNode.setAttribute("tagname", "row"); // 设置属性
  35. trNode.setAttribute("id", `tag_${global.id}`);
  36. global.id = global.id + 1
  37. let tdHtml = ''
  38. for (let j = 0; j < cellLength; j++) {
  39. 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);">&nbsp;</td>`
  40. global.id = global.id + 1
  41. }
  42. trNode.innerHTML = tdHtml
  43. if (isUp) {
  44. rowNode.parentNode.insertBefore(trNode, rowNode)
  45. }else{
  46. rowNode.parentNode.insertBefore(trNode, rowNode.nextSibling)
  47. }
  48. }

第五步:插入列

  1. /**
  2. * 插入列
  3. * @param {单元格} colls
  4. * @param {true:向左插入, false:向右插入} isLeft
  5. * @returns
  6. */
  7. export const addCell = (colls, isLeft) => {
  8. // const rowLength = curTable.rows.length // 行數量
  9. // 行转列
  10. let newArray = list[0].map(function (col, i) {
  11. return list.map(function (row) {
  12. return row[i]
  13. })
  14. })
  15. // 获取单元格所在的列
  16. let col = getCellsTrain(colls, newArray)
  17. if (col == -1) {
  18. return
  19. }
  20. // 这一列的id
  21. let arrId = newArray[col]
  22. let arr = []
  23. if (!((isLeft && col == 0) || (!isLeft && col == newArray.length-1))) {
  24. arr = isLeft ? newArray[col-1] : newArray[col+1]
  25. }
  26. let redoArr = []
  27. for (let i = 0; i < arrId.length; i++) {
  28. let td = document.getElementById(arrId[i])
  29. // 创建单元格节点
  30. let newCell = document.createElement('td')
  31. newCell.setAttribute("tagname", "entry")
  32. newCell.setAttribute("id", `tag_${global.id}`)
  33. global.id = global.id + 1
  34. newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
  35. newCell.innerHTML = '&nbsp;'
  36. if (arr.length>0) {
  37. if (arr[i] == arrId[i]) {
  38. if (redoArr.indexOf(arrId[i]) == -1) {
  39. let colspan = td.colSpan
  40. td.colSpan = colspan + 1
  41. redoArr.push(arrId[i])
  42. }
  43. continue
  44. }
  45. let tdBro = document.getElementById(arr[i])
  46. if (Array.from(new Set(arrId)).length < arrId.length) {
  47. if (td.parentNode.rowIndex != tdBro.parentNode.rowIndex) {
  48. if (isLeft) {
  49. td = tdBro.nextSibling
  50. }else{
  51. td = tdBro.previousSibling
  52. }
  53. }
  54. }
  55. }else {
  56. if (td.parentNode.rowIndex != i) {
  57. if (col == 0) {
  58. td = document.getElementById(newArray[col + 1][i])
  59. td.parentNode.insertBefore(newCell, td)
  60. } else {
  61. td = document.getElementById(newArray[col - 1][i])
  62. td.parentNode.appendChild(newCell)
  63. }
  64. continue
  65. }
  66. }
  67. if (isLeft) {
  68. !td ? curTable.rows[i].appendChild(newCell) : td.parentNode.insertBefore(newCell, td)
  69. } else {
  70. td.parentNode.insertBefore(newCell, td.nextSibling)
  71. }
  72. }
  73. }

第六步:删除行

  1. // colls: 单元格节点, curTable:表格节点
  2. export const delRow = (colls, curTable) => {
  3. const rowLength = curTable.rows.length // 行數量
  4. if (rowLength < 2) {
  5. alert('不能全部删除!')
  6. return
  7. }
  8. let row = colls.parentNode.rowIndex; // 行位置
  9. // let col = colls.cellIndex; // 列位置
  10. let rowNode = colls.parentNode // 行节点
  11. let tdNodeList = rowNode.getElementsByTagName('td')
  12. // 遍历这一行的单元格有没有跨行的, 如果跨行就将下一行的这一列的单元格跨行-1,相同跨列
  13. for (let i = 0; i < tdNodeList.length; i++) {
  14. let rowspan = tdNodeList[i].rowSpan
  15. if (rowspan>1) {
  16. let colspan = tdNodeList[i].colSpan
  17. let rowChild = curTable.rows[row+1]
  18. let colChild = rowChild.cells[i]
  19. let newCell = document.createElement('td')
  20. newCell.setAttribute("tagname", "entry")
  21. newCell.setAttribute("id", `tag_${global.id}`)
  22. global.id = global.id + 1
  23. newCell.setAttribute("rowspan", rowspan-1)
  24. newCell.setAttribute("colspan", colspan)
  25. newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
  26. newCell.innerHTML = '&nbsp;'
  27. rowChild.insertBefore(newCell, colChild)
  28. }
  29. }
  30. // 遍历有没有被跨行的,将被跨行的跨行数-1
  31. let arrId = list[row]
  32. for (let i = 0; i < arrId.length; i++) {
  33. let td = document.getElementById(arrId[i])
  34. let tdRow = td.parentNode.rowIndex;
  35. if (row == tdRow) {
  36. continue
  37. }
  38. let rowNum = td.rowSpan
  39. td.rowSpan = rowNum -1
  40. }
  41. rowNode.parentNode.removeChild(rowNode)
  42. }

第七步:删除列

  1. // colls: 单元格节点, curTable:表格节点
  2. export const delCell = (colls, curTable) => {
  3. const cellLength = getCellLength(curTable)
  4. if (cellLength < 2) {
  5. alert('不能全部删除!')
  6. return
  7. }
  8. // 行转列
  9. let newArray = list[0].map(function (col, i) {
  10. return list.map(function (row) {
  11. return row[i]
  12. })
  13. })
  14. let col = getCellsTrain(colls, newArray)
  15. if (col == -1) {
  16. return
  17. }
  18. // 这一列的值
  19. let arrId = newArray[col]
  20. for (let i = 0; i < arrId.length; i++) {
  21. let td = document.getElementById(arrId[i])
  22. let tdCol = getCellsTrain(td, newArray)
  23. // 判断单元格有没有被跨列,有,将跨列的 跨列-1
  24. if (tdCol != col) {
  25. let colNum = td.colSpan
  26. td.colSpan = colNum -1
  27. continue
  28. }
  29. // 判断单元格有没有跨列,有跨列,在该单元格的后面添加一个单元格 跨列-1
  30. let colspan = td.colSpan
  31. if (colspan>1) {
  32. let tdNext = td.nextSibling
  33. let rowspan = td.rowSpan
  34. let newCell = document.createElement('td')
  35. newCell.setAttribute("tagname", "entry")
  36. newCell.setAttribute("id", `tag_${global.id}`)
  37. global.id = global.id + 1
  38. newCell.setAttribute("rowspan", rowspan)
  39. newCell.setAttribute("colspan", colspan-1)
  40. newCell.setAttribute("style", "padding: 8px; line-height: 1.42857; vertical-align: top; border: 1px solid rgb(221, 221, 221);")
  41. newCell.innerHTML = '&nbsp;'
  42. td.parentNode.insertBefore(newCell, tdNext)
  43. }
  44. td.parentNode.removeChild(td)
  45. }
  46. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/668906
推荐阅读
相关标签
  

闽ICP备14008679号