当前位置:   article > 正文

使用小技巧实现el-table组件的合并行功能,ElementUI和ElementPlus都适用_el-table合并行

el-table合并行

前言

有时遇到一些需求,需要实现ElementUI或ElementPlus中,el-tabled组件合并单元格的功能,稍微了解一下它的数据格式,不难可以写出比合并方法。但是在鼠标经过单元行时,会出现高亮的行与鼠标经过的行不一致的BUG。因此还需要实现@cell-mouse-enter@cell-mouse-leave这两个方法,才可解决此问题。

一、多列合并

1.示例代码

(1)/src/views/Example/MergeCell/index_1.vue

  1. <template>
  2. <div class="merge-cell">
  3. <div class="merge-cell-navbar">记录一下 el-table 合并行小技巧</div>
  4. <div class="merge-cell-content">
  5. <div class="merge-cell-content-container">
  6. <el-table
  7. :data="tableData"
  8. border
  9. height="100%"
  10. :header-cell-style="
  11. {
  12. padding: '4px', // 设置Table表头单元内边距
  13. backgroundColor: '#e7f0ff', // 设置Table表头背景颜色
  14. borderColor: '#b6d1ff', // 设置Table表头边框颜色
  15. color: '#000', // 设置Table表头文字颜色
  16. fontSize: '13px', // 设置Table表头文字大小
  17. fontWeight: 'normal', // 设置Table表头文字粗细
  18. }
  19. "
  20. :span-method="handleSpanMethod"
  21. :row-class-name="handleRowClassName"
  22. @cell-mouse-enter="handleCellMouseEnter"
  23. @cell-mouse-leave="handleCellMouseLeave"
  24. >
  25. <el-table-column prop="zone" label="GameZone / 服务器区域 / 游戏区域" align="center" />
  26. <el-table-column prop="career" label="职业" width="180" align="center" />
  27. <el-table-column label="英雄" align="center">
  28. <el-table-column prop="hero" label="英雄姓名" width="280" align="center" />
  29. <el-table-column prop="firstSkill" label="一技能" width="220" align="center" />
  30. <el-table-column prop="secondSkill" label="二技能" width="220" align="center" />
  31. <el-table-column prop="thirdSkill" label="三技能" width="220" align="center" />
  32. <el-table-column label="操作" width="180" align="center">
  33. <template #default="scope">
  34. <el-tooltip effect="dark" content="收藏" placement="top" :enterable="false" :hide-after="0" @click="handleEditClick(scope.$index, scope.row)">
  35. <el-button size="small" circle>
  36. <el-icon size="18"><StarFilled /></el-icon>
  37. </el-button>
  38. </el-tooltip>
  39. </template>
  40. </el-table-column>
  41. </el-table-column>
  42. </el-table>
  43. </div>
  44. </div>
  45. </div>
  46. </template>
  47. <script>
  48. export default {
  49. data: () => ({
  50. tableData: [
  51. {
  52. zone: "王者一区",
  53. career: "坦克",
  54. hero: "亚瑟",
  55. firstSkill: "誓约之盾",
  56. secondSkill: "回旋打击",
  57. thirdSkill: "圣剑裁决",
  58. },
  59. {
  60. zone: "王者一区",
  61. career: "坦克",
  62. hero: "吕布",
  63. firstSkill: "方天画斩",
  64. secondSkill: "贪狼之握",
  65. thirdSkill: "魔神降世",
  66. },
  67. {
  68. zone: "王者一区",
  69. career: "坦克",
  70. hero: "项羽",
  71. firstSkill: "无畏冲锋",
  72. secondSkill: "破釜沉舟",
  73. thirdSkill: "霸王斩杀",
  74. },
  75. {
  76. zone: "王者一区",
  77. career: "战士",
  78. hero: "云缨",
  79. firstSkill: "断月",
  80. secondSkill: "追云",
  81. thirdSkill: "逐星",
  82. },
  83. {
  84. zone: "王者一区",
  85. career: "战士",
  86. hero: "赵怀真",
  87. firstSkill: "拨云见明",
  88. secondSkill: "气定神凝",
  89. thirdSkill: "阴阳逆转",
  90. },
  91. {
  92. zone: "王者二区",
  93. career: "刺客",
  94. hero: "镜",
  95. firstSkill: "开锋",
  96. secondSkill: "裂空",
  97. thirdSkill: "见影",
  98. },
  99. {
  100. zone: "王者二区",
  101. career: "刺客",
  102. hero: "澜",
  103. firstSkill: "破浪",
  104. secondSkill: "断空",
  105. thirdSkill: "处决",
  106. },
  107. {
  108. zone: "王者二区",
  109. career: "刺客",
  110. hero: "李白",
  111. firstSkill: "将进酒",
  112. secondSkill: "神来之笔",
  113. thirdSkill: "青莲剑歌",
  114. },
  115. {
  116. zone: "王者三区",
  117. career: "法师",
  118. hero: "妲己",
  119. firstSkill: "灵魂冲击",
  120. secondSkill: "偶像魅力",
  121. thirdSkill: "女王崇拜",
  122. },
  123. {
  124. zone: "王者三区",
  125. career: "射手",
  126. hero: "后羿",
  127. firstSkill: "多重箭矢",
  128. secondSkill: "落日余晖",
  129. thirdSkill: "灼日之矢",
  130. },
  131. {
  132. zone: "王者三区",
  133. career: "射手",
  134. hero: "鲁班7号",
  135. firstSkill: "河豚手雷",
  136. secondSkill: "无敌鲨嘴炮",
  137. thirdSkill: "空中支援",
  138. },
  139. {
  140. zone: "王者三区",
  141. career: "辅助",
  142. hero: "孙膑",
  143. firstSkill: "时空爆弹",
  144. secondSkill: "时之波动",
  145. thirdSkill: "时光流逝",
  146. },
  147. {
  148. zone: "王者三区",
  149. career: "辅助",
  150. hero: "庄周",
  151. firstSkill: "化蝶",
  152. secondSkill: "蝴蝶效应",
  153. thirdSkill: "天人合一",
  154. },
  155. ],
  156. first_row: {},
  157. second_row: {},
  158. }),
  159. methods: {
  160. /**
  161. * 合并单元格句柄方法
  162. */
  163. handleSpanMethod({
  164. row, // 行
  165. column, // 列
  166. rowIndex, // 行索引
  167. columnIndex, // 列索引
  168. }) {
  169. if (columnIndex === 0 || columnIndex === 1) {
  170. // 获取当前单元格的值
  171. const currentValue = row[column.property];
  172. // 获取上一行相同列的值
  173. const preRow = this.tableData[rowIndex - 1];
  174. const preValue = preRow ? preRow[column.property] : null;
  175. // 如果当前值和上一行的值相同,则将当前单元格隐藏
  176. if (currentValue === preValue) {
  177. return { rowspan: 0, colspan: 0 };
  178. } else {
  179. // 否则计算当前单元格应该跨越多少行
  180. let rowspan = 1;
  181. for (let i = rowIndex + 1; i < this.tableData.length; i++) {
  182. const nextRow = this.tableData[i];
  183. const nextValue = nextRow[column.property];
  184. if (nextValue === currentValue) {
  185. rowspan++;
  186. } else {
  187. break;
  188. }
  189. }
  190. return { rowspan, colspan: 1 };
  191. }
  192. }
  193. },
  194. /**
  195. * 鼠标移入表格事件句柄方法
  196. */
  197. handleCellMouseEnter(row, column, cell, event) {
  198. this.second_row = this.tableData.filter((item) => {
  199. return this.filterSameKeys(item, row, ["zone", "career"]);
  200. })[0];
  201. this.first_row = this.tableData.filter((item) => {
  202. return this.filterSameKeys(item, row, ["zone"]);
  203. })[0];
  204. },
  205. /**
  206. * 鼠标移出表格事件句柄方法
  207. */
  208. handleCellMouseLeave() {
  209. this.currentIndex = "";
  210. this.currentColumnIndex = "";
  211. this.first_row = {};
  212. this.second_row = {};
  213. },
  214. /**
  215. * 根据 keys 数组所有字段去做合并
  216. */
  217. filterSameKeys(item, row, keys) {
  218. let flag = true;
  219. keys.forEach((key) => {
  220. flag = flag && item[key] === row[key];
  221. });
  222. return flag;
  223. },
  224. /**
  225. * 给表格行添加自定义类名
  226. */
  227. handleRowClassName({ row }) {
  228. let flag1 = this.first_row == row ? "first_row" : "";
  229. let flag2 = this.second_row == row ? "second_row" : "";
  230. return `${flag1} ${flag2}`;
  231. },
  232. },
  233. };
  234. </script>
  235. <style lang="less" scoped>
  236. .merge-cell {
  237. display: flex;
  238. flex-direction: column;
  239. position: relative;
  240. width: 100%;
  241. height: 100%;
  242. overflow: hidden;
  243. .merge-cell-navbar {
  244. position: relative;
  245. width: 100%;
  246. height: 100px;
  247. background-color: #686868;
  248. text-align: center;
  249. line-height: 100px;
  250. color: #fff;
  251. font-size: 25px;
  252. }
  253. .merge-cell-content {
  254. position: relative;
  255. flex: 1;
  256. padding: 100px;
  257. overflow: hidden;
  258. .merge-cell-content-container {
  259. position: relative;
  260. width: 100%;
  261. height: 100%;
  262. overflow: auto;
  263. }
  264. }
  265. :deep(.el-table) {
  266. td .cell {
  267. padding: 2.5px 0;
  268. color: #686868;
  269. font-size: 13px;
  270. }
  271. .first_row td:nth-child(1),
  272. .second_row td:nth-child(1),
  273. .first_row.second_row td:nth-child(2) {
  274. background: #f5f7fa !important;
  275. }
  276. }
  277. /* ^ 设置Table表格边框颜色 */
  278. :deep(.el-table--border) {
  279. &::before {
  280. background-color: #b6d1ff;
  281. }
  282. &::after {
  283. background-color: #b6d1ff;
  284. }
  285. .el-table__cell {
  286. border-color: #b6d1ff;
  287. }
  288. .el-table__inner-wrapper {
  289. &::before {
  290. background-color: #b6d1ff;
  291. }
  292. &::after {
  293. background-color: #b6d1ff;
  294. }
  295. .el-table__border-left-patch {
  296. background-color: #b6d1ff;
  297. }
  298. }
  299. }
  300. /* / 设置Table表格边框颜色 */
  301. }
  302. </style>

2.运行效果

3.转载地址

https://juejin.cn/post/6930897196732645390

二、单列合并

1.示例代码

(1)/src/views/Example/MergeCell/index_2.vue

  1. <template>
  2. <div class="merge-cell">
  3. <div class="merge-cell-navbar">记录一下 el-table 合并行小技巧</div>
  4. <div class="merge-cell-content">
  5. <div class="merge-cell-content-container">
  6. <el-table
  7. :data="tableData"
  8. border
  9. height="100%"
  10. :header-cell-style="
  11. {
  12. padding: '4px', // 设置Table表头单元内边距
  13. backgroundColor: '#e7f0ff', // 设置Table表头背景颜色
  14. borderColor: '#b6d1ff', // 设置Table表头边框颜色
  15. color: '#000', // 设置Table表头文字颜色
  16. fontSize: '13px', // 设置Table表头文字大小
  17. fontWeight: 'normal', // 设置Table表头文字粗细
  18. }
  19. "
  20. :span-method="handleSpanMethod"
  21. >
  22. <el-table-column prop="zone" label="GameZone / 服务器区域 / 游戏区域" align="center" />
  23. <el-table-column prop="career" label="职业" width="180" align="center" />
  24. <el-table-column label="英雄" align="center">
  25. <el-table-column prop="hero" label="英雄姓名" width="280" align="center" />
  26. <el-table-column prop="firstSkill" label="一技能" width="220" align="center" />
  27. <el-table-column prop="secondSkill" label="二技能" width="220" align="center" />
  28. <el-table-column prop="thirdSkill" label="三技能" width="220" align="center" />
  29. <el-table-column label="操作" width="180" align="center">
  30. <template #default="scope">
  31. <el-tooltip effect="dark" content="收藏" placement="top" :enterable="false" :hide-after="0" @click="handleEditClick(scope.$index, scope.row)">
  32. <el-button size="small" circle>
  33. <el-icon size="18"><StarFilled /></el-icon>
  34. </el-button>
  35. </el-tooltip>
  36. </template>
  37. </el-table-column>
  38. </el-table-column>
  39. </el-table>
  40. </div>
  41. </div>
  42. </div>
  43. </template>
  44. <script>
  45. export default {
  46. data: () => ({
  47. tableData: [
  48. {
  49. zone: "王者一区",
  50. career: "坦克",
  51. hero: "亚瑟",
  52. firstSkill: "誓约之盾",
  53. secondSkill: "回旋打击",
  54. thirdSkill: "圣剑裁决",
  55. },
  56. {
  57. zone: "王者一区",
  58. career: "坦克",
  59. hero: "吕布",
  60. firstSkill: "方天画斩",
  61. secondSkill: "贪狼之握",
  62. thirdSkill: "魔神降世",
  63. },
  64. {
  65. zone: "王者一区",
  66. career: "坦克",
  67. hero: "项羽",
  68. firstSkill: "无畏冲锋",
  69. secondSkill: "破釜沉舟",
  70. thirdSkill: "霸王斩杀",
  71. },
  72. {
  73. zone: "王者一区",
  74. career: "战士",
  75. hero: "云缨",
  76. firstSkill: "断月",
  77. secondSkill: "追云",
  78. thirdSkill: "逐星",
  79. },
  80. {
  81. zone: "王者一区",
  82. career: "战士",
  83. hero: "赵怀真",
  84. firstSkill: "拨云见明",
  85. secondSkill: "气定神凝",
  86. thirdSkill: "阴阳逆转",
  87. },
  88. {
  89. zone: "王者二区",
  90. career: "刺客",
  91. hero: "镜",
  92. firstSkill: "开锋",
  93. secondSkill: "裂空",
  94. thirdSkill: "见影",
  95. },
  96. {
  97. zone: "王者二区",
  98. career: "刺客",
  99. hero: "澜",
  100. firstSkill: "破浪",
  101. secondSkill: "断空",
  102. thirdSkill: "处决",
  103. },
  104. {
  105. zone: "王者二区",
  106. career: "刺客",
  107. hero: "李白",
  108. firstSkill: "将进酒",
  109. secondSkill: "神来之笔",
  110. thirdSkill: "青莲剑歌",
  111. },
  112. {
  113. zone: "王者三区",
  114. career: "法师",
  115. hero: "妲己",
  116. firstSkill: "灵魂冲击",
  117. secondSkill: "偶像魅力",
  118. thirdSkill: "女王崇拜",
  119. },
  120. {
  121. zone: "王者三区",
  122. career: "射手",
  123. hero: "后羿",
  124. firstSkill: "多重箭矢",
  125. secondSkill: "落日余晖",
  126. thirdSkill: "灼日之矢",
  127. },
  128. {
  129. zone: "王者三区",
  130. career: "射手",
  131. hero: "鲁班7号",
  132. firstSkill: "河豚手雷",
  133. secondSkill: "无敌鲨嘴炮",
  134. thirdSkill: "空中支援",
  135. },
  136. {
  137. zone: "王者三区",
  138. career: "辅助",
  139. hero: "孙膑",
  140. firstSkill: "时空爆弹",
  141. secondSkill: "时之波动",
  142. thirdSkill: "时光流逝",
  143. },
  144. {
  145. zone: "王者三区",
  146. career: "辅助",
  147. hero: "庄周",
  148. firstSkill: "化蝶",
  149. secondSkill: "蝴蝶效应",
  150. thirdSkill: "天人合一",
  151. },
  152. ],
  153. first_row: {},
  154. second_row: {},
  155. }),
  156. methods: {
  157. /**
  158. * 合并单元格句柄方法
  159. */
  160. handleSpanMethod({
  161. row, // 行
  162. column, // 列
  163. rowIndex, // 行索引
  164. columnIndex, // 列索引
  165. }) {
  166. const rowspanArr = this.formatRowspanAndColspan(this.tableData, 'zone')
  167. if (columnIndex === 0) {
  168. // console.log('row =>', row)
  169. // console.log('column =>', column)
  170. // console.log('rowIndex =>', rowIndex)
  171. // console.log('columnIndex =>', columnIndex)
  172. // console.log('\n')
  173. return {
  174. rowspan: rowspanArr[rowIndex],
  175. colspan: 1
  176. }
  177. }
  178. },
  179. /**
  180. * 合并单元格辅助
  181. */
  182. formatRowspanAndColspan(tableList, keyName) {
  183. const keyNameList = []
  184. tableList.forEach(
  185. t => {keyNameList.push(t[keyName])}
  186. )
  187. // console.log('keyNameList =>', keyNameList)
  188. let prev // 上一个键名的索引
  189. let contin = 0 // 连续相同键名个数
  190. const computedList = [] // 计算后的键名列表
  191. for (let i = 0; i < keyNameList.length; i++) {
  192. if (computedList.length === 0) {
  193. computedList.push({ 'key': keyNameList[i], 'val': 1 })
  194. } else {
  195. if (keyNameList[prev] === keyNameList[i]) {
  196. contin++
  197. computedList.push({ 'key': keyNameList[i], 'val': 0 })
  198. } else {
  199. if (contin > 0) {
  200. const index = computedList.length - 1 - contin
  201. const key = computedList[index].key
  202. const val = computedList[index].val
  203. const obj = { 'key': key, 'val': val + contin}
  204. computedList.splice(index, 1, obj)
  205. }
  206. computedList.push({ 'key': keyNameList[i], 'val': 1 })
  207. contin = 0
  208. }
  209. }
  210. prev = i // 将 i 赋值给 prev,以便当下一次循环时获取上一个键值的索引
  211. }
  212. if (contin > 0) {
  213. const index = computedList.length - 1 - contin
  214. const key = computedList[index].key
  215. const val = computedList[index].val
  216. const obj = { 'key': key, 'val': val + contin}
  217. computedList.splice(index, 1, obj)
  218. }
  219. // console.log('computedList =>', computedList)
  220. const finalList = []
  221. computedList.forEach(
  222. t => {finalList.push(t.val)}
  223. )
  224. // console.log('finalList =>', finalList)
  225. return finalList
  226. },
  227. },
  228. };
  229. </script>
  230. <style lang="less" scoped>
  231. .merge-cell {
  232. display: flex;
  233. flex-direction: column;
  234. position: relative;
  235. width: 100%;
  236. height: 100%;
  237. overflow: hidden;
  238. .merge-cell-navbar {
  239. position: relative;
  240. width: 100%;
  241. height: 100px;
  242. background-color: #686868;
  243. text-align: center;
  244. line-height: 100px;
  245. color: #fff;
  246. font-size: 25px;
  247. }
  248. .merge-cell-content {
  249. position: relative;
  250. flex: 1;
  251. padding: 100px;
  252. overflow: hidden;
  253. .merge-cell-content-container {
  254. position: relative;
  255. width: 100%;
  256. height: 100%;
  257. overflow: auto;
  258. }
  259. }
  260. :deep(.el-table) {
  261. td .cell {
  262. padding: 2.5px 0;
  263. color: #686868;
  264. font-size: 13px;
  265. }
  266. .first_row td:nth-child(1),
  267. .second_row td:nth-child(1),
  268. .first_row.second_row td:nth-child(2) {
  269. background: #f5f7fa !important;
  270. }
  271. }
  272. /* ^ 设置Table表格边框颜色 */
  273. :deep(.el-table--border) {
  274. &::before {
  275. background-color: #b6d1ff;
  276. }
  277. &::after {
  278. background-color: #b6d1ff;
  279. }
  280. .el-table__cell {
  281. border-color: #b6d1ff;
  282. }
  283. .el-table__inner-wrapper {
  284. &::before {
  285. background-color: #b6d1ff;
  286. }
  287. &::after {
  288. background-color: #b6d1ff;
  289. }
  290. .el-table__border-left-patch {
  291. background-color: #b6d1ff;
  292. }
  293. }
  294. }
  295. /* / 设置Table表格边框颜色 */
  296. }
  297. </style>

2.运行效果

3.说明

单列合并的示例代码暂时还没修复当鼠标经过单元行时,会出现高亮的行与鼠标经过的行不一致的BUG,有空再研究修复一下。

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

闽ICP备14008679号