什么是OFD
OFD(Open Fixed-layout Documents的简称,意为开放版式文件)版式文档是版面呈现效果高度精确固定的电子文件,其呈现与设备无关。
与pdf文件相仿,具有格式独立、版面固定、固化呈现等特点。可以说OFD是中国版的PDF,但是在很多方面的性能优于PDF的同类文档。OFD也逐渐开始在电子发票、电子公文、电子证照等等的领域中应用。
国家正在推行办公文档的OFD格式。
简单来说,OFD是我们国家自主定制,PDF是美国公司制定。
目前OFD主要是在政府机关使用,不能直接打开文件,需要专业的OFD阅读器。
ofd.js实现ofd文件的预览功能
ofd.js是gitee上的一个开源项目JavaScript工具包。这里,我先感谢一下作者。
作者的gitee地址如下:
安装
npm i ofd.js
复制代码
引入
import {parseOfdDocument, renderOfd} from "ofd.js";
复制代码
核心代码
//其中ofd传入的file支持本地文件、二进制或者url、screenWidth为屏幕宽度
parseOfdDocument({
ofd: file,
success(res) {
//输出ofd每页的div
const divs = renderOfd(screenWidth, res);
//获取签章div的信息, 具体看demo
for(let ele of document.getElementsByName('seal_img_div')) {
this.addEventOnSealDiv(ele, JSON.parse(ele.dataset.sesSignature), JSON.parse(ele.dataset.signedInfo));
}
},
fail(error) {
console.log(error)
}
});
复制代码
OFD组件代码
<template>
<a-modal :title="title" :visible="visible" @cancel="handleCancel" width="70%" :footer="null">
<a-spin :spinning="loading" tip="加载中">
<div class="page-box">
<div class="option-list" v-if="ofdObj">
<div class="scale-icon" style="margin-left: 10px" @click="plus">
<!-- 放大 -->
<a-icon type="plus-circle" />
</div>
<div class="scale-icon" @click="minus">
<!-- 缩小 -->
<a-icon type="minus-circle" />
</div>
<div class="scale-icon">
<!-- 第一页 -->
<a-icon type="step-backward" @click="firstPage" />
</div>
<div class="scale-icon" @click="prePage">
<!-- 上一页 -->
<a-icon type="caret-left" />
</div>
<div class="scale-icon">
<!-- 当前页码和总页数 -->
{{ pageIndex }}/{{ pageCount }}
</div>
<div class="scale-icon" @click="nextPage">
<!-- 下一页 -->
<a-icon type="caret-right" />
</div>
<div class="scale-icon" @click="lastPage">
<!-- 最后一页 -->
<a-icon type="step-forward" />
</div>
</div>
</div>
<div class="modal-box" id="ofd-preview-box">
<!-- 文件区域 -->
<div class="main-section" :class="{ 'background-shadow': loadOverFlag }" id="content" ref="contentDiv"></div>
</div>
</a-spin>
</a-modal>
</template>
<script>
import { parseOfdDocument, renderOfd, renderOfdByScale, getPageScale, setPageScale } from 'ofd.js'
export default {
name: 'OfdPreview',
components: {},
props: {
title: {
type: String,
default: 'OFD文件预览',
},
fileUrl: {
type: String,
default: '',
},
},
data() {
return {
ofdObj: null,
pageIndex: 1,
pageCount: 0,
scale: 0,
loading: false,
visible: false,
loadOverFlag: false,
screenWidth: 1000,
}
},
watch: {},
computed: {},
methods: {
showModal() {
this.visible = true
this.$nextTick(() => {
this.screenWidth = document.getElementById('ofd-preview-box').getBoundingClientRect().width - 30
this.getOfdDocumentObj(this.fileUrl, this.screenWidth)
})
},
handleCancel(e) {
this.visible = false
},
getOfdDocumentObj(file, screenWidth) {
let that = this
this.loading = true
parseOfdDocument({
ofd: file,
success(res) {
that.ofdObj = res[0]
that.pageCount = res[0].pages.length
const divs = renderOfd(screenWidth, res[0])
that.displayOfdDiv(divs)
that.loadOverFlag = true
that.loading = false
},
fail(error) {
that.loading = false
console.log('OFD打开失败')
},
})
},
displayOfdDiv(divs) {
this.scale = getPageScale()
let contentDiv = document.getElementById('content')
contentDiv.innerHTML = ''
for (const div of divs) {
contentDiv.appendChild(div)
}
},
plus() {
setPageScale(++this.scale)
const divs = renderOfdByScale(this.ofdObj)
this.displayOfdDiv(divs)
},
minus() {
setPageScale(--this.scale)
const divs = renderOfdByScale(this.ofdObj)
this.displayOfdDiv(divs)
},
prePage() {
let contentDiv = document.getElementById('content')
let ele = contentDiv.children.item(this.pageIndex - 2)
if (ele) {
ele.scrollIntoView(true)
this.pageIndex = this.pageIndex - 1
}
},
firstPage() {
let contentDiv = document.getElementById('content')
let ele = contentDiv.firstElementChild
if (ele) {
ele.scrollIntoView(true)
this.pageIndex = 1
}
},
nextPage() {
let contentDiv = document.getElementById('content')
let ele = contentDiv.children.item(this.pageIndex)
if (ele) {
ele.scrollIntoView(true)
++this.pageIndex
}
},
lastPage() {
let contentDiv = document.getElementById('content')
let ele = contentDiv.lastElementChild
if (ele) {
ele.scrollIntoView(true)
this.pageIndex = contentDiv.childElementCount
}
},
},
created() {},
mounted() {},
}
</script>
<style lang="scss" scoped>
.wrapper {
}
.modal-box {
width: 100%;
height: 55vh;
overflow: auto;
}
.main-section {
width: 100%;
padding-top: 20px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
overflow: hidden;
position: relative;
}
.background-shadow {
background: #808080;
}
.page-box {
display: flex;
align-items: center;
justify-content: center;
height: 50px;
margin-bottom: 15px;
.option-list {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
}
}
.scale-icon {
display: flex;
cursor: pointer;
justify-content: center;
align-items: center;
width: 33px;
height: 28px;
border-radius: 1px;
font-weight: 500;
font-size: 18px;
color: #333333;
text-align: center;
padding: 2px;
}
.scale-icon :hover {
color: #1890ff;
}
.ant-spin-nested-loading > div > .ant-spin {
max-height: auto !important;
}
</style>
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END