上传word表格识别出table表格 转为二维数组并显示(vue)
一 、在main.js引入全局JS
import JSZip from 'jszip';
export default {
async extractWordTablesToArrays(file, callback) {
const Zip = new JSZip();
try {
// 解压 Word 文档
const zip = await Zip.loadAsync(file);
const documentXml = await zip.file("word/document.xml").async("string");
// 解析 XML
const parser = new DOMParser();
const documentDoc = parser.parseFromString(documentXml, "application/xml");
// 获取命名空间
const namespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
// 获取所有表格
const tables = documentDoc.getElementsByTagNameNS(namespace, "tbl");
const allTables = []; // 存储所有表格的二维数组
if (!tables || tables.length === 0) {
console.warn("未找到表格内容,请检查 XML 结构");
return [];
}
for (const table of tables) {
const rows = table.getElementsByTagNameNS(namespace, "tr");
const tableArray = []; // 当前表格的二维数组
for (const row of rows) {
const cells = row.getElementsByTagNameNS(namespace, "tc");
const rowArray = []; // 当前行的数据
// 存储已合并的单元格
let colSpanInfo = [];
for (let i = 0; i < cells.length; i++) {
const cell = cells[i];
let cellText = "";
// const paragraphs = cell.getElementsByTagNameNS(namespace, "p");
const paragraphs = cell.getElementsByTagName("w:p");
// 检查合并单元格属性
const gridSpan = cell.getElementsByTagNameNS(namespace, "gridSpan")[0];
const vMerge = cell.getElementsByTagNameNS(namespace, "vMerge")[0];
// 获取合并信息
let colspan = gridSpan ? parseInt(gridSpan.getAttribute("w:val"), 10) : 1;
let rowspan = 1;
if (vMerge && vMerge.getAttribute("w:val") === "restart") {
rowspan = 2; // 假设合并两行
} else if (vMerge && !vMerge.getAttribute("w:val")) {
continue; // 如果是合并单元格的继续部分,则跳过
}
// 为当前单元格初始化计数器
const currentLevelNumbers = {};
for (const paragraph of paragraphs) {
// 提取段落编号
let listPrefix = "";
// 初始化当前段落文本
let paragraphText = listPrefix ? `${listPrefix} ` : "";
const runs = paragraph.getElementsByTagName("w:r");
for (const run of runs) {
let textContent = "";
const texts = run.getElementsByTagName("w:t");
for (const text of texts) {
textContent += text.textContent;
}
// 检查格式
const rPr = run.getElementsByTagName("w:rPr")[0];
let formattedText = textContent;
if (rPr) {
const bold = rPr.getElementsByTagName("w:b").length > 0;
const italic = rPr.getElementsByTagName("w:i").length > 0;
const vertAlignElement = rPr.getElementsByTagName("w:vertAlign")[0];
if (bold) {
formattedText = `<b>${formattedText}</b>`;
}
if (italic) {
formattedText = `<i>${formattedText}</i>`;
}
if (vertAlignElement) {
const vertAlign = vertAlignElement.getAttribute("w:val");
if (vertAlign === "superscript") {
formattedText = `<sup>${formattedText}</sup>`;
} else if (vertAlign === "subscript") {
formattedText = `<sub>${formattedText}</sub>`;
}
}
}
paragraphText += formattedText;
}
// 处理换行符
const breaks = paragraph.getElementsByTagName("w:br");
for (const br of breaks) {
paragraphText += "<br>";
}
cellText += paragraphText; // 将段落文本添加到单元格文本
}
// 更新合并单元格的信息
if (colSpanInfo[i]) {
colspan = colSpanInfo[i].colspan;
}
// 保存当前单元格信息
rowArray.push({
text: cellText,
colspan: colspan,
rowspan: rowspan
});
// 记录跨列合并
if (colspan > 1) {
for (let j = 1; j < colspan; j++) {
colSpanInfo[i + j] = { colspan: 0 }; // 用 0 填充后续的列合并
}
}
}
tableArray.push(rowArray); // 添加当前行到表格数组
}
allTables.push(tableArray); // 添加当前表格到所有表格数组
}
console.log("解析后的二维数组:", allTables);
callback(allTables); // 返回处理后的 HTML
} catch (error) {
console.error("解析 Word 文件失败:", error);
return [];
}
},
getWordTablesThumbnails(tables, callback) {
let combinedHtml = `
<div style="display: flex; flex-wrap: wrap; gap: 16px; justify-content: start;">
`;
// 遍历每个表格,生成缩略图
tables.forEach((table, index) => {
let tableHtml = `
<div
style="
border: 1px solid #ccc;
padding: 8px;
width: 200px;
height: 150px;
overflow: hidden;
position: relative;
cursor: pointer;"
οnclick="document.getElementById('table-modal-${index}').style.display='block';"
>
<div
style="
transform: scale(0.3);
transform-origin: top left;
position: absolute;
width: 1000px;"
>
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>
`;
table.forEach((row) => {
tableHtml += `<tr>`;
// 遍历单元格
row.forEach((cell) => {
tableHtml += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span > ${cell.text}</span>
</td>
`;
});
tableHtml += `</tr>`;
});
tableHtml += `
</table>
</div>
</div>
<!-- 模态框显示原始表格 -->
<div
id="table-modal-${index}"
style="
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 9999;"
οnclick="this.style.display='none';"
>
<div
style="
background: #fff;
margin: 50px auto;
height: 80%;
padding: 20px;
max-width: 80%;
box-sizing:border-box;
max-width: 80%;
overflow: auto;"
>
`;
// 原始大小的表格内容
tableHtml += `
<table
border="1"
style="
border-collapse: collapse;
width: 100%;
text-align: center;
table-layout: auto;"
>
`;
table.forEach((row) => {
tableHtml += `<tr>`;
// 遍历单元格
row.forEach((cell) => {
tableHtml += `
<td
colspan="${cell.colspan || 1}"
rowspan="${cell.rowspan || 1}"
style=""
>
<span > ${cell.text}</span>
</td>
`;
});
tableHtml += `</tr>`;
});
tableHtml += `
</table>
</div>
</div>
`;
combinedHtml += tableHtml;
});
combinedHtml += `</div>`;
const container = document.createElement("div");
container.innerHTML = combinedHtml;
callback(container.innerHTML);
},
},
二、页面中 点击图片上传本地文件
<template>
<div>
<img src="@/assets/img/word.png" alt="" style="width: 30px; height: 30px" @click="clickUpload" />
<el-dialog
append-to-body
title="Add Academic Integrity Committee"
:visible.sync="addVisible"
width="80%"
:close-on-click-modal="false"
>
<div v-html="tablesHtml" class="wordTableHtml"></div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
tablesHtml: '',
tables: [], // 保存解析后的表格数据
addVisible: false
};
},
components: {},
methods: {
addVisCancle() {
this.addVisible = false;
},
clickUpload() {
this.tables = [];
var that = this;
const input = document.createElement('input');
input.type = 'file';
input.accept = '.docx'; // 限制为 Word 文件
input.addEventListener('change', function () {
const file = input.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function (e) {
that.$commonJS.extractWordTablesToArrays(file, function (wordTables) {
console.log('tablesHtml at line 61:', wordTables);
that.tables = wordTables;
that.$commonJS.getWordTablesThumbnails(wordTables, function (html) {
console.log('html at line 78:', html);
that.tablesHtml = html;
that.addVisible = true;
});
that.$emit('tables', that.tables, html);
});
};
reader.readAsArrayBuffer(file);
}
});
input.click();
},
}
};
</script>
```以下样式看情况 因为我需要 上标 下标 粗体 字体 的样式
```css
<style scoped>
::v-deep .wordTableHtml b span {
font-weight: bold !important;
}
::v-deep .wordTableHtml i span {
font-style: italic !important;
}
::v-deep .wordTableHtml sub span {
vertical-align: sub;
}
::v-deep .wordTableHtml sup span {
vertical-align: super;
}
::v-deep .wordTableHtml sub {
vertical-align: sub !important;
}
::v-deep .wordTableHtml sup {
vertical-align: super !important;
}
::v-deep .wordTableHtml span[style*='vertical-align: super'] {
vertical-align: super !important;
}
::v-deep .wordTableHtml span[style*='vertical-align: sub'] {
vertical-align: sub !important;
}
::v-deep .wordTableHtml table {
border: 0px !important;
border-collapse: collapse; /* 去除单元格间隙 */
width: auto;
margin: 0 auto !important;
table-layout: auto; /* 自动调整列宽 */
text-align: left;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
::v-deep .wordTableHtml table td,
.wordTableHtml table th::v-deep {
padding: 5px;
text-align: left !important;
word-wrap: break-word; /* 长单词自动换行 */
word-break: break-word;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
::v-deep .wordTableHtml table tbody tr td {
text-align: left !important;
border-left: none !important;
mso-border-left-alt: none !important;
border-right: none !important;
mso-border-right-alt: none !important;
border-top: none;
mso-border-top-alt: none !important;
border-bottom: none !important;
mso-border-bottom-alt: none !important;
border: 1px dashed #dcdfe6 !important;
border-left: 1px dashed #dcdfe6 !important;
border-right: 1px dashed #dcdfe6 !important;
word-break: keep-all !important;
/* text-align: justify !important; */
}
::v-deep .wordTableHtml table tr td p {
display: flex;
text-align: left !important;
align-items: center;
margin: 0;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
::v-deep .wordTableHtml table span {
color: #000000;
text-align: left !important;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
::v-deep .wordTableHtml table .color-highlight {
color: rgb(0, 130, 170) !important;
font-family: 'Charis SIL' !important;
font-size: 7.5pt !important;
mso-font-kerning: 1pt !important;
line-height: 10pt !important;
mos-line-height: 10pt !important;
}
::v-deep .wordTableHtml table tr:first-child td {
border-top: 1px solid #000 !important;
border-bottom: 1px solid #000 !important;
}
::v-deep .wordTableHtml table tr:last-of-type td {
border-bottom: 1px solid #000 !important;
}
</style>
原文地址:https://blog.csdn.net/shelter123456/article/details/144295595
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!