問題描述
本文記錄el-table
表頭合併的多種情況,並提出對應解決方案,估計能幫到部分道友
原生table知識點複習
- 我們知道:一個簡單的
table
表格一般由一個或多個tr
、th
或td
標籤組成(巢狀) tr
標籤定義表格行(table-row
即為tr
)th
標籤定義表頭(table-header
即為th
)td
標籤定義表格單元格
再複雜的表格還包括caption
、col
、colgroup
、thead
、tfoot
、tbody
等標籤,這裡暫不延伸
而合併單元格主要使用的是colspan
和rouspan
屬性,即為可設定橫跨列
和橫跨行
的值
而合併單元格主要使用的是colspan
和rouspan
屬性,即為可設定橫跨列
和橫跨行
的值
而合併單元格主要使用的是colspan
和rouspan
屬性,即為可設定橫跨列
和橫跨行
的值
知道這兩個屬性以後,我們結合一個具體demo來看,就很好的理解了
原生表格demo
假設我們需要做一個週一到週末的表格,記錄一下工作內容,如下效果圖:
對應程式碼是這樣的:
<table border="1">
<tr>
<th>工作日</th>
<th>工作日</th>
<th>工作日</th>
<th>工作日</th>
<th>工作日</th>
<th>週末</th>
<th>週末</th>
</tr>
<tr>
<th>週一</th>
<th>週二</th>
<th>週三</th>
<th>週四</th>
<th>週五</th>
<th>週六</th>
<th>週日</th>
</tr>
<tr>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>加班</td>
<td>加班</td>
</tr>
</table>
但是,我們想把五個工作日和兩個週末進行合併一下,這樣看起來更加優雅一些,如下需求
- 由圖示,我們知道第一行的工作日一共有5個,我們
先
把後4個工作日隱去使其消失, 再
讓第一個工作日橫跨5個單元格寬度,即橫跨5列(原本預設都是橫跨1列)
先隱去後四個工作日單元格
<tr>
<th>工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th>週末</th>
<th>週末</th>
</tr>
變成這樣的效果了
- 這樣的話,我們只需要,再讓第一個工作日單元格寬度變寬一些,佔據五個單元格,這樣的話,寬度有了,就把兩個週末擠回到原來正常的位置了
- 那,如何讓第一個工作日單元格,佔據五個單元格的寬度呢?
- 或者說,如何讓一個單元格橫跨5列?
- 很簡單:
<th colspan="5">工作日</th>
即可 rowspan
同理,不贅述
需求完成效果圖:
對應需求完成程式碼:
<table border="1">
<tr>
<th colspan="5">工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th style="display: none;">工作日</th>
<th colspan="2">週末</th>
<th style="display: none;">週末</th>
</tr>
<tr>
<th>週一</th>
<th>週二</th>
<th>週三</th>
<th>週四</th>
<th>週五</th>
<th>週六</th>
<th>週日</th>
</tr>
<tr>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>上班</td>
<td>加班</td>
<td>加班</td>
</tr>
</table>
所以,透過上面的demo,我們可以得出一個結論:
合併單元格規律結論
- 合併單元格需要 先隱藏相關單元格,再讓某個單元格橫向或豎向延伸寬度或高度
- 合併單元格需要 先隱藏相關單元格,再讓某個單元格橫跨列,或豎跨行
最後我們審查一下dom
元素,發現還真是這樣的
el-table單層表頭合併案例
無論是餓了麼UI還是Iview等相關的UI元件庫,都是給原生table套殼子封裝
的,所以若是需要合併相應單元格,我們依舊可以使用上述的思想方式
我們繼續透過案例來看一下,在UI元件庫中如何操作合併單元格
本文以表頭單元格合併舉例,若是有表體單元格合併的需求,可以看筆者之前的這篇文章:https://segmentfault.com/a/1190000040927939
案例一
效果圖:
程式碼:
header-cell-style
函式用於給表頭新增樣式,其返回的值會被新增到表頭對應樣式中去- 注意函式的形參中的
column.id
為單元格的class
類 - 大家最好列印一下,結合審查
dom
看類名
<template>
<el-table
:data="tableData"
border
style="width: 600"
:header-cell-style="headerCellStyle"
>
<el-table-column
prop="name"
label="姓名、年齡、家鄉"
width="150"
align="center"
></el-table-column>
<el-table-column
prop="age"
label="年齡"
width="150"
align="center"
></el-table-column>
<el-table-column
prop="home"
label="家鄉"
width="150"
align="center"
></el-table-column>
<el-table-column
prop="hobby"
label="愛好"
width="150"
align="center"
></el-table-column>
</el-table>
</template>
<script>
export default {
data() {
return {
tableData: [
{
name: "孫悟空",
age: 500,
home: "花果山水簾洞",
hobby: "大鬧天宮",
},
{
name: "豬八戒",
age: 88,
home: "高老莊",
hobby: "吃包子",
},
{
name: "沙和尚",
age: 1000,
home: "通天河",
hobby: "游泳",
},
{
name: "唐僧",
age: 99999,
home: "東土大唐",
hobby: "取西經",
},
],
};
},
methods: {
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 第一步:設定表頭的第0列暫不操作,將地1列和第2列隱去使其消失
if ((columnIndex == 1) | (columnIndex == 2)) {
return { display: "none" };
}
// 第二步, 由於1、2列沒有了,後續列就會貼上來(後續列往左錯位問題)
if ((rowIndex == 0) & (columnIndex == 0)) {
// 解決後續列錯位問題,就是將隱去的第1、2列的位置再補上,透過第0列來補
this.$nextTick(() => {
// 原來第0列只佔據一個位置,現在要去佔據三個位置。即佔據三列,即設定為橫向三個單元格
document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
// 這裡的column.id實際是dom元素的class,故用點.不用井#,可審查dom驗證
// 透過設定原生的colspan屬性,讓原來的第一列只佔據一個單元格的表頭佔據3個單元格即可
});
}
},
},
};
</script>
<style lang="less">
.el-table {
th {
font-weight: bold;
color: #333;
}
}
</style>
看,基本上一樣的用法:先隱藏再設定橫跨豎跨單元格
colspan='number' 屬性,設定單元格可以橫跨幾列(預設一個單元格橫向只佔據一列)
案例二
效果圖:
程式碼:
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 第一步:隱去第2列單元格
if (columnIndex == 2) {
return { display: "none" };
}
// 第二步,讓第1列單元格橫跨兩列(預設單元格只是橫跨一列)
if ((rowIndex == 0) & (columnIndex == 1)) {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
});
}
},
案例三
效果圖:
程式碼:
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 第一步:隱去第3列單元格
if (columnIndex == 3) {
return { display: "none" };
}
// 第二步,讓第2列單元格橫跨兩列(預設單元格只是橫跨一列)
if ((rowIndex == 0) & (columnIndex == 2)) {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
});
}
},
案例四
效果圖:
程式碼:
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 第一步:隱去第1、2、3列單元格
let hideColArr = [1, 2, 3];
if (hideColArr.includes(columnIndex)) {
return { display: "none" };
}
// 第二步,讓第0列單元格橫跨四列(預設單元格只是橫跨一列)
if ((rowIndex == 0) & (columnIndex == 0)) {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "4");
});
}
},
el-table多級表頭合併案例
- 多級表頭,需要進一步透過
rowIndex
去找到對應的單元格 - 因為單層表頭,表頭只有1行,
rowIndex
肯定是0,所以寫不寫都無所謂 - 但是多級表頭有不少行,所以需要使用
columnIndex,rowIndex
進一步定位單元格 - 類似於透過
X軸 Y軸
的座標定位到某個單元格位置
案例五
效果圖:
程式碼:
html部門需要el-table-column標籤進行巢狀
<template>
<el-table
:data="tableData"
border
style="width: 600"
:header-cell-style="headerCellStyle"
>
<el-table-column prop="name" label="姓名" width="150" align="center">
<el-table-column
prop="name"
label="三列基礎資訊"
width="150"
align="center"
></el-table-column>
</el-table-column>
<el-table-column prop="name" label="年齡" width="150" align="center">
<el-table-column
prop="age"
label="年齡"
width="150"
align="center"
></el-table-column>
</el-table-column>
<el-table-column prop="name" label="家鄉" width="150" align="center">
<el-table-column
prop="home"
label="家鄉"
width="150"
align="center"
></el-table-column>
</el-table-column>
<el-table-column
prop="hobby"
label="愛好"
width="150"
align="center"
></el-table-column>
</el-table>
</template>
js部分繼續先隱藏再延伸相關單元格
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 把第1列第1行和第2列第1行的單元格隱去
if ((columnIndex == 1) | (columnIndex == 2)) {
if (rowIndex == 1) { // 加上rowIndex精準定位
return { display: "none" };
}
}
// 然後讓第0列第1行的單元格橫向佔據3個單元格位置填充剛剛隱去導致的空白
if ((columnIndex == 0) & (rowIndex == 1)) { // 加上rowIndex精準定位
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
});
}
},
案例六
效果圖:
程式碼:
依舊是巢狀
<template>
<el-table
:data="tableData"
border
style="width: 600"
:header-cell-style="headerCellStyle"
>
<el-table-column
prop="name"
label="基本資訊(姓名、年齡、家鄉)"
align="center"
>
</el-table-column>
<el-table-column
prop="age"
label="年齡"
align="center"
>
</el-table-column>
<el-table-column
prop="home"
label="家鄉"
align="center"
>
</el-table-column>
<el-table-column prop="kind" label="所屬種族" align="center">
</el-table-column>
<el-table-column label="重要資訊" align="center">
<el-table-column label="公開重要資訊" align="center">
<el-table-column prop="nickname" label="法號" align="center">
</el-table-column>
<el-table-column prop="hobby" label="愛好&性格" align="center">
</el-table-column>
<el-table-column prop="personality" label="性格" align="center">
</el-table-column>
</el-table-column>
<el-table-column label="保密重要資訊" align="center">
<el-table-column prop="bornBackground" label="出身背景" align="center">
</el-table-column>
<el-table-column prop="skill" label="技能" align="center">
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
</template>
<style lang="less">
.el-table {
th {
font-weight: bold;
color: #333;
}
}
</style>
先找到dom,再操作dom
<script>
export default {
data() {
return {
tableData: [
{
name: "孫悟空",
age: 500,
home: "花果山水簾洞",
kind: "monkey",
nickname: "鬥戰勝佛",
hobby: "大鬧天宮",
personality: "勇敢堅韌、疾惡如仇",
bornBackground: "仙石孕育而生",
skill: "72變、筋斗雲",
},
{
name: "豬八戒",
age: 88,
home: "高老莊",
kind: "pig",
nickname: "淨壇使者",
hobby: "吃包子",
personality: "好吃懶做、貪圖女色",
bornBackground: "天蓬元帥錯投豬胎",
skill: "36變",
},
{
name: "沙和尚",
age: 1000,
home: "通天河",
kind: "human",
nickname: "金身羅漢",
hobby: "游泳",
personality: "憨厚老實、任勞任怨",
bornBackground: "捲簾大將被貶下界",
skill: "18變",
},
{
name: "唐僧",
age: 99999,
home: "東土大唐",
kind: "human",
nickname: "檀功德佛",
hobby: "取西經",
personality: "謙恭儒雅、愚善固執",
bornBackground: "金蟬子轉世",
skill: "念緊箍咒",
},
],
};
},
methods: {
headerCellStyle({ row, column, rowIndex, columnIndex }) {
/**
* 合併:基本資訊(姓名、年齡、家鄉)單元格【透過行與列的索引來合併】
* */
let colArr = [1, 2];
if (colArr.includes(columnIndex)) {
if (rowIndex == 0) {
// 把第1列第0行和第2列第0行的單元格隱去
return { display: "none" };
}
}
if ((columnIndex == 0) & (rowIndex == 0)) {
// 把第0列第0行的單元格橫向延伸,補上剛剛隱去的單元格位置,並上個色
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
});
return { background: "pink" };
}
/**
* 合併:重要資訊--->公開重要資訊--->愛好性格單元格 【透過單元格的文字內容來合併】
* */
if (column.label == "性格") {
return { display: "none" };
}
if (column.label == "愛好&性格") {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
});
return { background: "orange" }; // 不加這個也行,加了只是為了更好區分
}
/**
* 重要!重要!重要!
* 我們想要合併表頭的單元格,需要先找到對應單元格
* 可以透過列column物件的label或者行與列索引來找到,找到以後進行隱藏或合併
* 也可以遍歷行row陣列找,不過會麻煩一些,個人建議透過column來找
* */
// 透過column找
if (column.label == "技能") {
return { background: "#baf" };
}
// 透過row找
for (const item of row) {
if (item.label == "重要資訊") {
this.$nextTick(() => {
document.querySelector(`.${item.id}`).style.background = "#ea66a6";
});
break;
}
}
},
},
};
</script>
- 還可以,直接透過column.label找到對應單元格,然後進行合併單元格操作,不使用rowIndex和columnIndex了
- 這種方式,在某些情況下,會更加方便
- 但無論哪種方式,本質思路都是先找到單元格,再進行合併相關操作
headerCellStyle({ row, column, rowIndex, columnIndex }) {
// 第一部分的合併
if (column.label == "年齡") {
return { display: "none" };
}
if (column.label == "家鄉") {
return { display: "none" };
}
if (column.label == "基本資訊(姓名、年齡、家鄉)") {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "3");
});
return { background: "pink" };
}
// 第二部分的合併
if (column.label == "性格") {
return { display: "none" };
}
if (column.label == "愛好&性格") {
this.$nextTick(() => {
document.querySelector(`.${column.id}`).setAttribute("colspan", "2");
});
return { background: "orange" };
}
},
總結
讀到這裡,大家對錶頭合併相關問題應該都能應對了,若是還有不能應對的,可以發到評論區,大家一塊幫忙解決
A good memory is better than a bad pen. Write it down...