闲话少说直接上效果
导出的文件效果如下
在浏览器上的效果如下
直接上完整代码
<!DOCTYPE html>
<html lang="en">
<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>请求数据生成表格并导出到xls/csv文件等</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100%;
}
.tableDom {
margin: 15px 15px;
display: flex;
flex-direction: column;
}
.tableDom .btn_content button {
font-size: 14px;
border: none;
padding: 3px 5px;
background-color: #197bfe;
color: #fafafa;
border-radius: 5px;
cursor: pointer;
}
.tableDom .btn_content button:hover {
box-shadow: 0 0 5px #197bfe;
}
table {
height: auto;
margin: 5px 0;
border-collapse: collapse;
line-height: 25px;
border-spacing: 0px;
/* border-bottom: 1px solid #c1c1c1; */
}
table th,
table td {
padding: 0 5px;
color: #333;
text-align: center;
border: 1px solid #c1c1c1;
font-size: 14px;
}
/* 滚动条宽度 */
::-webkit-scrollbar {
width: 4px;
height: 4px;
background-color: transparent;
}
/* 滚动条颜色 */
::-webkit-scrollbar-thumb {
background-color: #a8a8a8;
}
table thead {
color: white;
background-color: #efefef;
}
table thead th {
border-bottom: none;
}
table tbody {
display: block;
/* width: calc(100%); */
/*这里的8px是滚动条的宽度*/
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
table thead tr,
table tbody tr {
box-sizing: border-box;
table-layout: fixed;
display: table;
width: 100%;
}
table tbody tr:nth-of-type(odd) {
background: #ffffff;
}
table tbody tr:nth-of-type(even) {
background: #e0e0e0;
}
table tbody tr td {
border-bottom: none;
}
table body {
border-bottom: 1px solid #c1c1c1 !important;
}
</style>
</head>
<body>
<div class="tableDom">
<div class="btn_content">
<button id="daochu">导出数据</button>
<button id="shuaxin">刷新数据</button>
</div>
<table id="sgs_table">
<thead id="sgsthead"></thead>
<tbody id="sgstbody"></tbody>
</table>
</div>
</body>
<script>
// 声明导出csv方法
// 当页面渲染完成再执行
window.onload = function () {
// 获取两个按钮和表格标签
const exportBtn = document.getElementById("daochu"); // 导出按钮
const refreshBtn = document.getElementById("shuaxin"); // 刷新按钮
const showThead = document.getElementById("sgsthead"); // 获取table的thead标签
const showTbody = document.getElementById("sgstbody"); // 获取table的tbody标签
// 声明空盒子用于承载获取出来的数据
var data = null;
// 模拟请求获取数据 里面的代码可以根据自己的业务拆出来用
setTimeout(function () {
// 我的后端给我返回的数据也是这样以中文作为对象的键值的,当然,每个人遇到的后端都不一样,看个人吧
let getData = [
{ 姓名: "新氦锂铍硼", 语文: "110", 数学: "99", 英语: "104" },
{ 姓名: "碳氮氧氟氖", 语文: "99", 数学: "115", 英语: "98" },
{ 姓名: "钠镁铝硅灵", 语文: "120", 数学: "102", 英语: "14" },
{ 姓名: "流氯氩钾钙", 语文: "88", 数学: "66", 英语: "39" },
];
data = getData; // 将数据存到盒子中,在后续导出csv文件的时候需要用到,数据的键值就是姓名,语文数学英语这些,也是导出后的表格的表头
// 当数据请求回来之后执行下面操作
// 这里用于判断获取回来的数据是否是数组而且数组长度是否为0
if (
Object.prototype.toString.call(getData) === "[object Array]" &&
getData.length > 0
) {
let newTheadTH = []; // 声明一个空数组,承载表头对象,此处就是获取渲染页面上的表头数据
for (let key in getData[0]) {
newTheadTH.push({
title: key,
widths: 150, // 这是给页面上的表格设定宽度用的,当然这里目前用不上,我就不改了,后面不需要这个可以自行删除,不影响的
});
}
// 以上就获取到了表格头部了,然后先渲染
let newHtmlTh = "";
newTheadTH.forEach(function (item, index) {
newHtmlTh = newHtmlTh.concat(
'<th width="' + item.widths + '">' + item.title + "</th>"
);
});
// 生成头标签
showThead.innerHTML = "<tr>" + newHtmlTh + "</tr>";
// 生成完头部标签就要生成tbody的数据内容了
let trTag = ""; // 创建空字符串承载 tr
// 开始生成tbody的所有内容
getData.forEach(function (item, index) {
let forInKey = "";
for (let key in item) {
forInKey = forInKey.concat(
'<td width="150">' + item[key] + "</td>"
);
}
trTag = trTag.concat("<tr>" + forInKey + "</tr>");
});
showTbody.innerHTML = trTag;
}
// 如果请求回来的数据不为数组或者是数组但是长度为0的时候 判空
else {
showThead.innerHTML = "<tr><td>请求数据为空</td></tr>";
}
}, 1000);
// 刷新按钮我的方法我就不写了,就是将setTimeout内部的代码重新执行一遍
refreshBtn.addEventListener("click", function () {
// 刷新的逻辑
});
// 导出按钮*****主要的重点
exportBtn.addEventListener("click", function () {
let csvContent = Object.keys(data[0]).join(",") + "\n"; // 生成导导出表格的头部
for (let i = 0; i < data.length; i++) {
let row = [];
for (let key in data[i]) {
if (data[i].hasOwnProperty(key)) {
row.push(data[i][key]);
}
}
csvContent += row.join(",") + "\n";
}
// return
// 创建一个Blob对象
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8" });
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
console.log("navigator:", navigator);
navigator.msSaveBlob(blob, "导出.csv");
} else {
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "导出.csv";
// 将a标签添加到DOM中,模拟点击下载链接,最后移除a标签
link.style.display = "none";
document.body.appendChild(link);
// console.log(link);
link.click();
document.body.removeChild(link);
}
});
};
</script>
</html>
然后我解析导出csv文件那个方法,因为其他方法一看就懂
首先我们要知道csv文件格式是什么样的,直接看对应图就好啦, 红色指向表格的表头,在csv文件的第一行,注意,第一行是表头,每一列用一个英文逗号分隔,
蓝色指向是表数据,也是逗号分隔的,注意csv文件中是表头是不变的,也就是说,从csv文件的第二行开始是每一行的数据,可能我说的不是很清除,直接看图理解快一些
在导出方法中的以下这一块代码说的就是先把csv文件的头部存好,然后从第二行开始每一行都是一列数据,我用 /n 就是再强制转行,就是为了达到我需要的数据格式
for (let i = 0; i < data.length; i++) {
let row = [];
for (let key in data[i]) {
if (data[i].hasOwnProperty(key)) {
row.push(data[i][key]);
}
}
csvContent += row.join(",") + "\n";
}
然后下面的判断就是看看浏览是什么样的,就使用哪一种方法导出csv文件,也就是wps文件
console.log("navigator:", navigator); // 打印是什么牛马浏览器
navigator.msSaveBlob(blob, "导出.csv");
} else {
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "导出.csv";
// 将a标签添加到DOM中,模拟点击下载链接,最后移除a标签
link.style.display = "none";
document.body.appendChild(link);
// console.log(link);
link.click();
document.body.removeChild(link);
}