上传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>
相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
沈梦研5 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
轻口味6 小时前
Vue.js 组件之间的通信模式
vue.js
浪浪山小白兔6 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter
limit for me7 小时前
react上增加错误边界 当存在错误时 不会显示白屏
前端·react.js·前端框架