赞
踩
有时遇到一些需求,需要实现ElementUI或ElementPlus中,el-tabled组件合并单元格的功能,稍微了解一下它的数据格式,不难可以写出比合并方法。但是在鼠标经过单元行时,会出现高亮的行与鼠标经过的行不一致的BUG。因此还需要实现@cell-mouse-enter和@cell-mouse-leave这两个方法,才可解决此问题。
(1)/src/views/Example/MergeCell/index_1.vue
- <template>
- <div class="merge-cell">
- <div class="merge-cell-navbar">记录一下 el-table 合并行小技巧</div>
-
- <div class="merge-cell-content">
- <div class="merge-cell-content-container">
- <el-table
- :data="tableData"
- border
- height="100%"
- :header-cell-style="
- {
- padding: '4px', // 设置Table表头单元内边距
- backgroundColor: '#e7f0ff', // 设置Table表头背景颜色
- borderColor: '#b6d1ff', // 设置Table表头边框颜色
- color: '#000', // 设置Table表头文字颜色
- fontSize: '13px', // 设置Table表头文字大小
- fontWeight: 'normal', // 设置Table表头文字粗细
- }
- "
- :span-method="handleSpanMethod"
- :row-class-name="handleRowClassName"
- @cell-mouse-enter="handleCellMouseEnter"
- @cell-mouse-leave="handleCellMouseLeave"
- >
- <el-table-column prop="zone" label="GameZone / 服务器区域 / 游戏区域" align="center" />
- <el-table-column prop="career" label="职业" width="180" align="center" />
- <el-table-column label="英雄" align="center">
- <el-table-column prop="hero" label="英雄姓名" width="280" align="center" />
- <el-table-column prop="firstSkill" label="一技能" width="220" align="center" />
- <el-table-column prop="secondSkill" label="二技能" width="220" align="center" />
- <el-table-column prop="thirdSkill" label="三技能" width="220" align="center" />
- <el-table-column label="操作" width="180" align="center">
- <template #default="scope">
- <el-tooltip effect="dark" content="收藏" placement="top" :enterable="false" :hide-after="0" @click="handleEditClick(scope.$index, scope.row)">
- <el-button size="small" circle>
- <el-icon size="18"><StarFilled /></el-icon>
- </el-button>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table-column>
- </el-table>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data: () => ({
- tableData: [
- {
- zone: "王者一区",
- career: "坦克",
- hero: "亚瑟",
- firstSkill: "誓约之盾",
- secondSkill: "回旋打击",
- thirdSkill: "圣剑裁决",
- },
- {
- zone: "王者一区",
- career: "坦克",
- hero: "吕布",
- firstSkill: "方天画斩",
- secondSkill: "贪狼之握",
- thirdSkill: "魔神降世",
- },
- {
- zone: "王者一区",
- career: "坦克",
- hero: "项羽",
- firstSkill: "无畏冲锋",
- secondSkill: "破釜沉舟",
- thirdSkill: "霸王斩杀",
- },
- {
- zone: "王者一区",
- career: "战士",
- hero: "云缨",
- firstSkill: "断月",
- secondSkill: "追云",
- thirdSkill: "逐星",
- },
- {
- zone: "王者一区",
- career: "战士",
- hero: "赵怀真",
- firstSkill: "拨云见明",
- secondSkill: "气定神凝",
- thirdSkill: "阴阳逆转",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "镜",
- firstSkill: "开锋",
- secondSkill: "裂空",
- thirdSkill: "见影",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "澜",
- firstSkill: "破浪",
- secondSkill: "断空",
- thirdSkill: "处决",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "李白",
- firstSkill: "将进酒",
- secondSkill: "神来之笔",
- thirdSkill: "青莲剑歌",
- },
- {
- zone: "王者三区",
- career: "法师",
- hero: "妲己",
- firstSkill: "灵魂冲击",
- secondSkill: "偶像魅力",
- thirdSkill: "女王崇拜",
- },
- {
- zone: "王者三区",
- career: "射手",
- hero: "后羿",
- firstSkill: "多重箭矢",
- secondSkill: "落日余晖",
- thirdSkill: "灼日之矢",
- },
- {
- zone: "王者三区",
- career: "射手",
- hero: "鲁班7号",
- firstSkill: "河豚手雷",
- secondSkill: "无敌鲨嘴炮",
- thirdSkill: "空中支援",
- },
- {
- zone: "王者三区",
- career: "辅助",
- hero: "孙膑",
- firstSkill: "时空爆弹",
- secondSkill: "时之波动",
- thirdSkill: "时光流逝",
- },
- {
- zone: "王者三区",
- career: "辅助",
- hero: "庄周",
- firstSkill: "化蝶",
- secondSkill: "蝴蝶效应",
- thirdSkill: "天人合一",
- },
- ],
-
- first_row: {},
- second_row: {},
- }),
- methods: {
- /**
- * 合并单元格句柄方法
- */
- handleSpanMethod({
- row, // 行
- column, // 列
- rowIndex, // 行索引
- columnIndex, // 列索引
- }) {
- if (columnIndex === 0 || columnIndex === 1) {
- // 获取当前单元格的值
- const currentValue = row[column.property];
-
- // 获取上一行相同列的值
- const preRow = this.tableData[rowIndex - 1];
- const preValue = preRow ? preRow[column.property] : null;
-
- // 如果当前值和上一行的值相同,则将当前单元格隐藏
- if (currentValue === preValue) {
- return { rowspan: 0, colspan: 0 };
- } else {
- // 否则计算当前单元格应该跨越多少行
- let rowspan = 1;
- for (let i = rowIndex + 1; i < this.tableData.length; i++) {
- const nextRow = this.tableData[i];
- const nextValue = nextRow[column.property];
- if (nextValue === currentValue) {
- rowspan++;
- } else {
- break;
- }
- }
- return { rowspan, colspan: 1 };
- }
- }
- },
-
- /**
- * 鼠标移入表格事件句柄方法
- */
- handleCellMouseEnter(row, column, cell, event) {
- this.second_row = this.tableData.filter((item) => {
- return this.filterSameKeys(item, row, ["zone", "career"]);
- })[0];
-
- this.first_row = this.tableData.filter((item) => {
- return this.filterSameKeys(item, row, ["zone"]);
- })[0];
- },
-
- /**
- * 鼠标移出表格事件句柄方法
- */
- handleCellMouseLeave() {
- this.currentIndex = "";
- this.currentColumnIndex = "";
- this.first_row = {};
- this.second_row = {};
- },
-
- /**
- * 根据 keys 数组所有字段去做合并
- */
- filterSameKeys(item, row, keys) {
- let flag = true;
- keys.forEach((key) => {
- flag = flag && item[key] === row[key];
- });
- return flag;
- },
-
- /**
- * 给表格行添加自定义类名
- */
- handleRowClassName({ row }) {
- let flag1 = this.first_row == row ? "first_row" : "";
- let flag2 = this.second_row == row ? "second_row" : "";
- return `${flag1} ${flag2}`;
- },
- },
- };
- </script>
-
- <style lang="less" scoped>
- .merge-cell {
- display: flex;
- flex-direction: column;
- position: relative;
- width: 100%;
- height: 100%;
- overflow: hidden;
-
- .merge-cell-navbar {
- position: relative;
- width: 100%;
- height: 100px;
- background-color: #686868;
- text-align: center;
- line-height: 100px;
- color: #fff;
- font-size: 25px;
- }
-
- .merge-cell-content {
- position: relative;
- flex: 1;
- padding: 100px;
- overflow: hidden;
-
- .merge-cell-content-container {
- position: relative;
- width: 100%;
- height: 100%;
- overflow: auto;
- }
- }
-
- :deep(.el-table) {
-
- td .cell {
- padding: 2.5px 0;
- color: #686868;
- font-size: 13px;
- }
-
- .first_row td:nth-child(1),
- .second_row td:nth-child(1),
- .first_row.second_row td:nth-child(2) {
- background: #f5f7fa !important;
- }
- }
-
- /* ^ 设置Table表格边框颜色 */
- :deep(.el-table--border) {
- &::before {
- background-color: #b6d1ff;
- }
- &::after {
- background-color: #b6d1ff;
- }
- .el-table__cell {
- border-color: #b6d1ff;
- }
- .el-table__inner-wrapper {
- &::before {
- background-color: #b6d1ff;
- }
- &::after {
- background-color: #b6d1ff;
- }
- .el-table__border-left-patch {
- background-color: #b6d1ff;
- }
- }
- }
- /* / 设置Table表格边框颜色 */
- }
- </style>
https://juejin.cn/post/6930897196732645390
(1)/src/views/Example/MergeCell/index_2.vue
- <template>
- <div class="merge-cell">
- <div class="merge-cell-navbar">记录一下 el-table 合并行小技巧</div>
-
- <div class="merge-cell-content">
- <div class="merge-cell-content-container">
- <el-table
- :data="tableData"
- border
- height="100%"
- :header-cell-style="
- {
- padding: '4px', // 设置Table表头单元内边距
- backgroundColor: '#e7f0ff', // 设置Table表头背景颜色
- borderColor: '#b6d1ff', // 设置Table表头边框颜色
- color: '#000', // 设置Table表头文字颜色
- fontSize: '13px', // 设置Table表头文字大小
- fontWeight: 'normal', // 设置Table表头文字粗细
- }
- "
- :span-method="handleSpanMethod"
- >
- <el-table-column prop="zone" label="GameZone / 服务器区域 / 游戏区域" align="center" />
- <el-table-column prop="career" label="职业" width="180" align="center" />
- <el-table-column label="英雄" align="center">
- <el-table-column prop="hero" label="英雄姓名" width="280" align="center" />
- <el-table-column prop="firstSkill" label="一技能" width="220" align="center" />
- <el-table-column prop="secondSkill" label="二技能" width="220" align="center" />
- <el-table-column prop="thirdSkill" label="三技能" width="220" align="center" />
- <el-table-column label="操作" width="180" align="center">
- <template #default="scope">
- <el-tooltip effect="dark" content="收藏" placement="top" :enterable="false" :hide-after="0" @click="handleEditClick(scope.$index, scope.row)">
- <el-button size="small" circle>
- <el-icon size="18"><StarFilled /></el-icon>
- </el-button>
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table-column>
- </el-table>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- export default {
- data: () => ({
- tableData: [
- {
- zone: "王者一区",
- career: "坦克",
- hero: "亚瑟",
- firstSkill: "誓约之盾",
- secondSkill: "回旋打击",
- thirdSkill: "圣剑裁决",
- },
- {
- zone: "王者一区",
- career: "坦克",
- hero: "吕布",
- firstSkill: "方天画斩",
- secondSkill: "贪狼之握",
- thirdSkill: "魔神降世",
- },
- {
- zone: "王者一区",
- career: "坦克",
- hero: "项羽",
- firstSkill: "无畏冲锋",
- secondSkill: "破釜沉舟",
- thirdSkill: "霸王斩杀",
- },
- {
- zone: "王者一区",
- career: "战士",
- hero: "云缨",
- firstSkill: "断月",
- secondSkill: "追云",
- thirdSkill: "逐星",
- },
- {
- zone: "王者一区",
- career: "战士",
- hero: "赵怀真",
- firstSkill: "拨云见明",
- secondSkill: "气定神凝",
- thirdSkill: "阴阳逆转",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "镜",
- firstSkill: "开锋",
- secondSkill: "裂空",
- thirdSkill: "见影",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "澜",
- firstSkill: "破浪",
- secondSkill: "断空",
- thirdSkill: "处决",
- },
- {
- zone: "王者二区",
- career: "刺客",
- hero: "李白",
- firstSkill: "将进酒",
- secondSkill: "神来之笔",
- thirdSkill: "青莲剑歌",
- },
- {
- zone: "王者三区",
- career: "法师",
- hero: "妲己",
- firstSkill: "灵魂冲击",
- secondSkill: "偶像魅力",
- thirdSkill: "女王崇拜",
- },
- {
- zone: "王者三区",
- career: "射手",
- hero: "后羿",
- firstSkill: "多重箭矢",
- secondSkill: "落日余晖",
- thirdSkill: "灼日之矢",
- },
- {
- zone: "王者三区",
- career: "射手",
- hero: "鲁班7号",
- firstSkill: "河豚手雷",
- secondSkill: "无敌鲨嘴炮",
- thirdSkill: "空中支援",
- },
- {
- zone: "王者三区",
- career: "辅助",
- hero: "孙膑",
- firstSkill: "时空爆弹",
- secondSkill: "时之波动",
- thirdSkill: "时光流逝",
- },
- {
- zone: "王者三区",
- career: "辅助",
- hero: "庄周",
- firstSkill: "化蝶",
- secondSkill: "蝴蝶效应",
- thirdSkill: "天人合一",
- },
- ],
-
- first_row: {},
- second_row: {},
- }),
- methods: {
- /**
- * 合并单元格句柄方法
- */
- handleSpanMethod({
- row, // 行
- column, // 列
- rowIndex, // 行索引
- columnIndex, // 列索引
- }) {
- const rowspanArr = this.formatRowspanAndColspan(this.tableData, 'zone')
- if (columnIndex === 0) {
- // console.log('row =>', row)
- // console.log('column =>', column)
- // console.log('rowIndex =>', rowIndex)
- // console.log('columnIndex =>', columnIndex)
- // console.log('\n')
- return {
- rowspan: rowspanArr[rowIndex],
- colspan: 1
- }
- }
- },
-
- /**
- * 合并单元格辅助
- */
- formatRowspanAndColspan(tableList, keyName) {
- const keyNameList = []
- tableList.forEach(
- t => {keyNameList.push(t[keyName])}
- )
- // console.log('keyNameList =>', keyNameList)
-
- let prev // 上一个键名的索引
- let contin = 0 // 连续相同键名个数
- const computedList = [] // 计算后的键名列表
- for (let i = 0; i < keyNameList.length; i++) {
- if (computedList.length === 0) {
- computedList.push({ 'key': keyNameList[i], 'val': 1 })
- } else {
- if (keyNameList[prev] === keyNameList[i]) {
- contin++
- computedList.push({ 'key': keyNameList[i], 'val': 0 })
- } else {
- if (contin > 0) {
- const index = computedList.length - 1 - contin
- const key = computedList[index].key
- const val = computedList[index].val
- const obj = { 'key': key, 'val': val + contin}
- computedList.splice(index, 1, obj)
- }
- computedList.push({ 'key': keyNameList[i], 'val': 1 })
- contin = 0
- }
- }
-
- prev = i // 将 i 赋值给 prev,以便当下一次循环时获取上一个键值的索引
- }
- if (contin > 0) {
- const index = computedList.length - 1 - contin
- const key = computedList[index].key
- const val = computedList[index].val
- const obj = { 'key': key, 'val': val + contin}
- computedList.splice(index, 1, obj)
- }
- // console.log('computedList =>', computedList)
-
- const finalList = []
- computedList.forEach(
- t => {finalList.push(t.val)}
- )
- // console.log('finalList =>', finalList)
-
- return finalList
- },
- },
- };
- </script>
-
- <style lang="less" scoped>
- .merge-cell {
- display: flex;
- flex-direction: column;
- position: relative;
- width: 100%;
- height: 100%;
- overflow: hidden;
-
- .merge-cell-navbar {
- position: relative;
- width: 100%;
- height: 100px;
- background-color: #686868;
- text-align: center;
- line-height: 100px;
- color: #fff;
- font-size: 25px;
- }
-
- .merge-cell-content {
- position: relative;
- flex: 1;
- padding: 100px;
- overflow: hidden;
-
- .merge-cell-content-container {
- position: relative;
- width: 100%;
- height: 100%;
- overflow: auto;
- }
- }
-
- :deep(.el-table) {
-
- td .cell {
- padding: 2.5px 0;
- color: #686868;
- font-size: 13px;
- }
-
- .first_row td:nth-child(1),
- .second_row td:nth-child(1),
- .first_row.second_row td:nth-child(2) {
- background: #f5f7fa !important;
- }
- }
-
- /* ^ 设置Table表格边框颜色 */
- :deep(.el-table--border) {
- &::before {
- background-color: #b6d1ff;
- }
- &::after {
- background-color: #b6d1ff;
- }
- .el-table__cell {
- border-color: #b6d1ff;
- }
- .el-table__inner-wrapper {
- &::before {
- background-color: #b6d1ff;
- }
- &::after {
- background-color: #b6d1ff;
- }
- .el-table__border-left-patch {
- background-color: #b6d1ff;
- }
- }
- }
- /* / 设置Table表格边框颜色 */
- }
- </style>
单列合并的示例代码暂时还没修复当鼠标经过单元行时,会出现高亮的行与鼠标经过的行不一致的BUG,有空再研究修复一下。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。