在使用 HTML 的表格标签时,当表格项过多时,左右拉动时,希望固定几列不随水平滚动条滚动,表头也不随竖直方向滚动而滚动。在使用组件库的时候,通常都有成熟的API。
思路一: 是在查找资料中发现的,创建多个 table 将首尾需要固定的列使用单独的表格,然后对需要固定的列所在表格添加position: absolute
,本人想通过一个表格实现,未使用该方法。
思路二: 通过position: sticky
实现
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./css.css">
<script src="https://cdn.bootcss.com/xlsx/0.11.5/xlsx.core.min.js"></script>
</head>
<body>
<div id="table-to-excel">导出Excel</div>
<div class="contain">
<div class="table-self" id="table-outlayer">
<table class="table">
<thead class="tb-thead">
<tr class="tr-th">
<th class="th">
<div>列一</div>
</th>
<th class="th" id="th-2">
<div>列二</div>
</th>
<th class="th">
<div>列三</div>
</th>
<th class="th">
<div>列四</div>
</th>
<th class="th">
<div>列五</div>
</th>
<th class="th">
<div>列六</div>
</th>
<th class="th">
<div>列七</div>
</th>
<th class="th">
<div>列八</div>
</th>
<th class="th">
<div>列九</div>
</th>
<th class="th">
<div>列十</div>
</th>
<th class="th" id="th-11">
<div>列十一</div>
</th>
</tr>
</thead>
<tbody class="tb-tbody">
<tr class="tr-tb">
<td class="td">行一列一</td>
<td class="td" id="1-2">行一列二</td>
<td class="td">行一列三</td>
<td class="td">行一列四</td>
<td class="td">行一列五</td>
<td class="td">行一列六</td>
<td class="td">行一列七</td>
<td class="td">行一列八</td>
<td class="td">行一列九</td>
<td class="td">行一列十</td>
<td class="td" id="1-11">行一列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行二列一</td>
<td class="td" id="2-2">行二列二</td>
<td class="td">行二列三</td>
<td class="td">行二列四</td>
<td class="td">行二列五</td>
<td class="td">行二列六</td>
<td class="td">行二列七</td>
<td class="td">行二列八</td>
<td class="td">行二列九</td>
<td class="td">行二列十</td>
<td class="td" id="2-11">行二列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行三列一</td>
<td class="td" id="3-2">行三列二</td>
<td class="td">行三列三</td>
<td class="td">行三列四</td>
<td class="td">行三列五</td>
<td class="td">行三列六</td>
<td class="td">行三列七</td>
<td class="td">行三列八</td>
<td class="td">行三列九</td>
<td class="td">行三列十</td>
<td class="td" id="3-11">行三列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行四列一</td>
<td class="td" id="4-2">行四列二</td>
<td class="td">行四列三</td>
<td class="td">行四列四</td>
<td class="td">行四列五</td>
<td class="td">行四列六</td>
<td class="td">行四列七</td>
<td class="td">行四列八</td>
<td class="td">行四列九</td>
<td class="td">行四列十</td>
<td class="td" id="4-11">行四列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行五列一</td>
<td class="td" id="5-2">行五列二</td>
<td class="td">行五列三</td>
<td class="td">行五列四</td>
<td class="td">行五列五</td>
<td class="td">行五列六</td>
<td class="td">行五列七</td>
<td class="td">行五列八</td>
<td class="td">行五列九</td>
<td class="td">行五列十</td>
<td class="td" id="5-11">行五列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行六列一</td>
<td class="td" id="6-2">行六列二</td>
<td class="td">行六列三</td>
<td class="td">行六列四</td>
<td class="td">行六列五</td>
<td class="td">行六列六</td>
<td class="td">行六列七</td>
<td class="td">行六列八</td>
<td class="td">行六列九</td>
<td class="td">行六列十</td>
<td class="td" id="6-11">行六列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行七列一</td>
<td class="td" id="7-2">行七列二</td>
<td class="td">行七列三</td>
<td class="td">行七列四</td>
<td class="td">行七列五</td>
<td class="td">行七列六</td>
<td class="td">行七列七</td>
<td class="td">行七列八</td>
<td class="td">行七列九</td>
<td class="td">行七列十</td>
<td class="td" id="7-11">行七列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行八列一</td>
<td class="td" id="8-2">行八列二</td>
<td class="td">行八列三</td>
<td class="td">行八列四</td>
<td class="td">行八列五</td>
<td class="td">行八列六</td>
<td class="td">行八列七</td>
<td class="td">行八列八</td>
<td class="td">行八列九</td>
<td class="td">行八列十</td>
<td class="td" id="8-11">行八列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行九列一</td>
<td class="td" id="9-2">行九列二</td>
<td class="td">行九列三</td>
<td class="td">行九列四</td>
<td class="td">行九列五</td>
<td class="td">行九列六</td>
<td class="td">行九列七</td>
<td class="td">行九列八</td>
<td class="td">行九列九</td>
<td class="td">行九列十</td>
<td class="td" id="9-11">行九列十一</td>
</tr>
<tr class="tr-tb">
<td class="td">行十列一</td>
<td class="td" id="10-2">行十列二</td>
<td class="td">行十列三</td>
<td class="td">行十列四</td>
<td class="td">行十列五</td>
<td class="td">行十列六</td>
<td class="td">行十列七</td>
<td class="td">行十列八</td>
<td class="td">行十列九</td>
<td class="td">行十列十</td>
<td class="td" id="11-11">行十列十一</td>
</tr>
</tbody>
</table>
</div>
</div>
<script>
document.getElementById('table-to-excel').addEventListener('click', function () {
console.log('click');
let tableDom = document.getElementById("table-outlayer");
let blob = toSheet(XLSX.utils.table_to_sheet(tableDom));
let a = document.createElement("a"); // 创建a标签
a.download = "下载表格.xlsx"; // 设置下载的表格名
a.href = window.URL.createObjectURL(blob); // 设置a标签的链接
document.body.appendChild(a); // 将a标签添加到页面
a.click(); // 设置a标签触发点击事件
document.body.removeChild(a); //移除a标签
})
function toSheet(sheet, sheetName) {
sheetName = sheetName || "sheet1";
var workbook = {
SheetNames: [sheetName],
Sheets: {},
};
workbook.Sheets[sheetName] = sheet;
// 生成excel的配置项
var wopts = {
bookType: "xlsx", // 要生成的文件类型
bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
type: "binary",
};
var wbout = XLSX.write(workbook, wopts);
var blob = new Blob([s2ab(wbout)], {
type: "application/octet-stream;charset=utf-8",
});
// 字符串转ArrayBuffer
function s2ab(s) {
var buf = new ArrayBuffer(s.length);
var view = new Uint8Array(buf);
for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
return buf;
}
return blob;
}
window.addEventListener("scroll", function scroll() {
console.log(document.getElementById("table-outlayer").clientWidth);
console.log(document.getElementById("table-outlayer").scrollWidth);
console.log(document.getElementById("table-outlayer").scrollLeft);
if (document.getElementById("table-outlayer").clientWidth ===
document.getElementById("table-outlayer").scrollWidth) {
// 不存在 水平方向的滚动
return
} else {
// 滚动条在最左边时
if (document.getElementById("table-outlayer").scrollLeft === 0) {
document.getElementById("th-2").style.boxShadow = "none"
for (let tbLine = 0; tbLine <= 10; tbLine++) {
document.getElementById(`${tbLine+1}-2`) ? document.getElementById(`${tbLine+1}-2`).style.boxShadow = "none" : ""
}
} else {
document.getElementById("th-2").style.boxShadow = "4px 0 4px -2px #ccc"
for (let tbLine = 0; tbLine <= 10; tbLine++) {
document.getElementById(`${tbLine+1}-2`) ? document.getElementById(`${tbLine+1}-2`).style.boxShadow = "4px 0 4px -2px #ccc" :
""
}
}
// 滚动条在最右边时
if (document.getElementById("table-outlayer").scrollLeft +
document.getElementById("table-outlayer").clientWidth ===
document.getElementById("table-outlayer").scrollWidth) {
document.getElementById("th-11").style.boxShadow = "none"
for (let tbLine = 0; tbLine <= 10; tbLine++) {
document.getElementById(`${tbLine+1}-11`) ? document.getElementById(`${tbLine+1}-11`).style.boxShadow = "none" : ""
}
} else {
document.getElementById("th-11").style.boxShadow = "-4px 0 4px -2px #ccc"
for (let tbLine = 0; tbLine <= 10; tbLine++) {
document.getElementById(`${tbLine+1}-11`) ? document.getElementById(`${tbLine+1}-11`).style.boxShadow =
"-4px 0 4px -2px #ccc" : ""
}
}
}
},
true)
</script>
</body>
</html>
css 代码
.contain {
position: relative;
width: 1400px;
height: 600px;
}
.contain .table-self {
position: relative;
left: 0;
top: 0;
width: 100%;
height: 500px;
overflow: auto;
border: 1px solid #e8e8e8;
background-color: #fff;
}
.contain .table-self .table {
position: relative;
left: 0;
top: 0;
width: 100%;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-spacing: 0;
border-collapse: separate;
text-align: center;
}
.contain .table-self .table .tb-thead {
position: relative;
left: 0;
top: 0;
}
/* // 表格表头第一行 不随竖直方向滚动条滚动 */
.contain .table-self .table .tb-thead .tr-th .th {
z-index: 99;
position: sticky;
left: 0;
top: 0;
padding: 16px;
border-left: 1px solid #e8e8e8;
border-bottom: 1px solid #e8e8e8;
color: #000000d9;
font-size: 14px;
line-height: 1.5;
font-weight: 500;
background-color: #fafafa;
word-break: break-word;
overflow-wrap: break-word;
}
.contain .table-self .table .tb-thead .tr-th .th div {
width: 200px;
}
/* // 表格表头第一行, 第一列 不随水平方向滚动条滚动 */
.contain .table-self .table .tb-thead .tr-th .th:first-child {
position: sticky;
left: 0;
top: 0;
z-index: 999;
border-left: none;
}
/* // 表格表头第一行, 第二列 不随水平方向滚动条滚动 */
.contain .table-self .table .tb-thead .tr-th .th:nth-child(2) {
position: sticky;
left: 232px;
/* 第二列left 的距离要是第一列的宽度 */
top: 0;
z-index: 998;
}
.contain .table-self .table .tb-thead .tr-th .th:nth-last-child(2) {
border-right: 1px solid #e8e8e8;
}
/* // 表格表头第一行, 最后一列 不随水平方向滚动条滚动 */
.contain .table-self .table .tb-thead .tr-th .th:last-child {
position: sticky;
right: 0;
top: 0;
z-index: 999;
border-left: none;
box-shadow: -4px 0 4px -2px #ccc;
}
.contain .table-self .table .tb-tbody .tr-tb .td {
padding: 16px;
border-left: 1px solid #e8e8e8;
border-bottom: 1px solid #e8e8e8;
color: #000000a6;
font-size: 14px;
line-height: 1.5;
background-color: #fff;
}
/* // 表格内容第一列不随水平方向滚动条滚动 */
.contain .table-self .table .tb-tbody .tr-tb .td:first-child {
position: sticky;
left: 0;
top: 0;
z-index: 9;
border-left: none;
border-top: none;
}
/* // 表格内容第二列不随水平方向滚动条滚动 */
.contain .table-self .table .tb-tbody .tr-tb .td:nth-child(2) {
position: sticky;
left: 232px;
/* 第二列的 left 的距离要是第一列的宽度 */
top: 0;
z-index: 8;
border-top: none;
}
.contain .table-self .table .tb-tbody .tr-tb .td:nth-last-child(2) {
border-right: 1px solid #e8e8e8;
}
/* // 表格内容最后一列不随水平方向滚动条滚动 */
.contain .table-self .table .tb-tbody .tr-tb .td:last-child {
position: sticky;
right: 0;
top: 0;
z-index: 9;
border-left: none;
box-shadow: -4px 0 4px -2px #ccc;
}
其中附带了到处excel功能