上传word表格识别出table表格 转为二维数组并显示(vue)

一 、在main.js引入全局JS

javascript 复制代码
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);
    },


    },

二、页面中 点击图片上传本地文件

javascript 复制代码
<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>
相关推荐
崔庆才丨静觅43 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax