vue中回显word、Excel文件
记录一下最近的功能点,方便下次copy。支出多个sheets 切换展示和单元格合并。

引入插件
vue2版本,插件的版本比较低
json
"highlight.js": "^11.11.1",
"mammoth": "^1.11.0",
"marked": "^4.0.0",
"xlsx": "^0.18.5"
"@vue-office/docx": "1.6.3",
"@vue/composition-api": "1.7.2",
javascript
import mammoth from 'mammoth'
import VueOfficeDocx from '@vue-office/docx'
import * as XLSX from 'xlsx'
import { marked } from 'marked'
import hljs from 'highlight.js'
import '@vue-office/docx/lib/index.css'
code
javascript
<template>
<div>
<div class="info-tips" v-loading="isloading" :element-loading-text="$constants.G_COMPANY_INFO.loadingText" v-if="isWordDOCX">
<vue-office-docx @rendered="renderedHandler" :src="this.originalFile.fileUrl" style="width: 100%;height: 100%" />
</div>
<div class="info-tips" v-loading="isloading" :element-loading-text="$constants.G_COMPANY_INFO.loadingText" v-if="isWord">
<div class="word-content" v-html="wordHtml"></div>
</div>
<div class="info-tips" v-loading="isloading" :element-loading-text="$constants.G_COMPANY_INFO.loadingText" v-if="isTxt">
<pre class="word-content" v-if="wordHtml">{{ wordHtml }}</pre>
</div>
<div class="info-tips" v-loading="isloading" :element-loading-text="$constants.G_COMPANY_INFO.loadingText" v-if="isMarkDown">
<div class="word-content" v-html="wordHtml"></div>
</div>
<div class="info-tips" v-loading="isloading" :element-loading-text="$constants.G_COMPANY_INFO.loadingText" v-if="isExcel">
<div class="excel-wraper">
<table class="excel-table">
<tbody>
<tr v-for="(row, rowIndex) in currentExcelData" :key="rowIndex">
<template v-for="(cell, cellindex) in row">
<td
v-if="!isShowTd(row, rowIndex, cellindex)"
:colspan="getColspanNum(rowIndex, cellindex, row)"
:rowspan="getRowspanNum(rowIndex, cellindex, row)"
:key="cellindex"
>
{{ cell }}
</td>
</template>
</tr>
</tbody>
</table>
</div>
<ul class="excel-name">
<li :class="index == currentIndex ? 'actived' : ''" v-for="(item, index) in excelData" @click="getCurrentExcel(index)" :key="index">
{{ item.sheetName }}
</li>
</ul>
</div>
</div>
</template>
<script>
data(){
return{
isloading:true,
isWord: false,
wordHtml: undefined,
isExcel: false,
excelData: [],
currentExcelData: [],
currentIndex: 0,
isWordDOCX: false,
isTxt: false,
isMarkDown: false,
}
},
methods:{
//根据XLSX解析出来的merges数组来判断表格是否需要合并
isShowTd(row, rowIndex, cellindex) {
let hiddlen = false
let curmerges = this.excelData[this.currentIndex].merges
curmerges.forEach((item, index) => {
// 纵向合并判断
if (item.s.c == item.e.c && rowIndex > item.s.r && rowIndex <= item.e.r && cellindex == item.s.c) {
if (row[item.s.c] == null) {
hiddlen = true
}
}
// 横向合并判断
if (item.s.r == item.e.r && rowIndex == item.s.r && cellindex > item.s.c && cellindex <= item.e.c) {
if (row[cellindex] == null) {
hiddlen = true
}
}
})
return hiddlen
},
// docx文件加载完成回调
renderedHandler() {
this.isloading = false
},
//多个sheets切换
getCurrentExcel(index) {
this.currentIndex = index
this.currentExcelData = this.excelData[index].excelData
},
//由于表格是遍历解析出来的数据得到的,这里表格的自动合并行并不会删除被合并的单元格,需要手动隐藏被合并的单元格的列数据
getColspanNum(rowIndex, cellindex) {
let num = null
let merges = this.excelData[this.currentIndex].merges
merges.forEach((item, index) => {
if (item.s.r == item.e.r && rowIndex == item.s.r && cellindex == item.s.c) {
num = item.e.c - item.s.c + 1
}
})
return num
},
//由于表格是遍历解析出来的数据得到的,这里表格的自动合并行并不会删除被合并的单元格,需要手动隐藏被合并的单元格的行数据
getRowspanNum(rowIndex, cellindex) {
let num = null
let merges = this.excelData[this.currentIndex].merges
merges.forEach((item, index) => {
if (item.s.c == item.e.c && rowIndex == item.s.r && cellindex == item.s.c) {
num = item.e.r - item.s.r + 1
}
})
return num
},
previewWord() {
this.$service.systemget(this.$apis.getPreviewFile, { fileId }).then(
async res => {
if (res.data.status == 0) {
this.originalFile = res.data.data.originalFile ? res.data.data.originalFile : this.datas
} else {
this.originalFile = this.datas
}
this.isExcel = this.getExcelType()
this.isTxt = this.getWordTypeTXT()
if (this.isWord || this.isExcel) {
const response = await fetch(this.originalFile.fileUrl, {
method: 'GET',
mode: 'cors',
credentials: 'omit'
})
if (!response.ok) {
this.isloading = false
throw new Error('Http错误:' + response.status + '-' + response.statusText)
}
const arrayBuffer = await response.arrayBuffer()
const u8Array = new Uint8Array(arrayBuffer)
const ext = this.originalFile.fileUrl
.split('.')
.pop()
.toLowerCase()
if (ext === 'docx') {
const result = await mammoth.convertToHtml({ arrayBuffer: arrayBuffer, ignoreEmptyParagraphs: false })
this.wordHtml = result.value
this.isloading = false
} else if (ext == 'xlsx' || ext == 'xls') {
const workbook = XLSX.read(u8Array, { type: 'array', cellDates: true, cellNF: false })
let SheetNames = workbook.SheetNames
let Sheets = workbook.Sheets
SheetNames.forEach((item, index) => {
const worksheet = Sheets[item]
const merges = worksheet['!merges']
let excelData = XLSX.utils.sheet_to_json(worksheet, { header: 1, raw: false })
let max = 0
excelData.forEach(item => {
if (item.length > max) {
max = item.length
}
})
excelData.forEach((item, index) => {
if (item.length < max && index > 0) {
let n = max - item.length
for (let i = 0; i < n; i++) {
item.push(null)
}
}
})
this.excelData.push({
sheetName: item,
excelData,
max,
merges
})
this.currentExcelData = this.excelData[0].excelData
this.currentIndex = 0
})
this.isloading = false
}
} else if (this.isTxt || this.isMarkDown) {
const response = await fetch(this.originalFile.fileUrl)
if (!response.ok) {
this.isloading = false
throw new Error('Http错误:' + response.status + '-' + response.statusText)
}
this.wordHtml = await response.text()
if (this.isMarkDown) {
const renderer = new marked.Renderer()
renderer.code = (code, language) => {
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext'
console.log(validLanguage)
return `<pre class="hljs"><code>${hljs.highlight(code, { language: validLanguage }).value}</code></pre>`
}
this.wordHtml = marked(this.wordHtml, { renderer })
}
this.isloading = false
}
},
err => {
this.preivewDatas = this.datas
this.originalFile = this.datas
this.isloading = false
this.globalHandleConnectTimeoutErr(err)
}
)
}
}
</script>