上传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>
相关推荐
GIS好难学几秒前
考研出分24小时,人类精神状态图鉴
前端·考研·gis·gis开发·webgis·地信
斯~内克8 分钟前
React Router 完全指南:从基础到高级实践
前端·react.js·前端框架
m0_7482323910 分钟前
qwenvl 以及qwenvl 2 模型架构理解
android·前端·后端
冲!!13 分钟前
vue3中ref和reactive响应式数据、ref模板引用(组合式和选项式区别)、组件ref的使用
前端·javascript·vue.js
匹马夕阳14 分钟前
React vs Vue3深度对比与使用场景分析
前端·react.js·前端框架
Swift社区41 分钟前
【Swift 算法实战】利用 KMP 算法高效求解最短回文串
vue.js·算法·leetcode
七灵微43 分钟前
【前端】简单原生实例合集html,css,js
前端·css·html
祈澈菇凉43 分钟前
2025年React Hooks的进阶面试题130题及其答案解析..
前端·react.js·前端框架
Neo Evolution1 小时前
每天一个Flutter开发小项目 (6) : 表单与验证的专业实践 - 构建预约应用
android·开发语言·前端·javascript·flutter
大橙子房1 小时前
AI学习第六天-python的基础使用-趣味图形
前端·python·学习