OFD文件预览组件

什么是OFD

OFD(Open Fixed-layout Documents的简称,意为开放版式文件)版式文档是版面呈现效果高度精确固定的电子文件,其呈现与设备无关。

与pdf文件相仿,具有格式独立、版面固定、固化呈现等特点。可以说OFD是中国版的PDF,但是在很多方面的性能优于PDF的同类文档。OFD也逐渐开始在电子发票、电子公文、电子证照等等的领域中应用。

国家正在推行办公文档的OFD格式。

简单来说,OFD是我们国家自主定制,PDF是美国公司制定。

目前OFD主要是在政府机关使用,不能直接打开文件,需要专业的OFD阅读器。

ofd.js实现ofd文件的预览功能

ofd.js是gitee上的一个开源项目JavaScript工具包。这里,我先感谢一下作者。

作者的gitee地址如下:

gitee.com/Donal/ofd.j…

安装

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
喜欢就支持一下吧
点赞0 分享