v3+ts+vite移动端H5预览docx,xlsx,pdf

923 阅读2分钟

由于移动端H5项目需要预览不同形式的文件,自己的项目是v3+ts+vite,用的setup语法塘.虽然解决方案与网上大同小异,但还是踩了一些坑,在这里记录一下。因为用的第三方库,不了解一些具体的数据类型,因此偷懒用了any去处理。

pdf预览

主要通过pdfjs-dist预览,主要考虑到可以实现自己的定制化需求,直接npm安装即可使用,我的版本是2.5.207

    npm install pdfjs-dist
    //ts 引入
    import * as PDFJS from 'pdfjs-dist'
    //添加这行解决worker.
    PDFJS.GlobalWorkerOptions.workerSrc ='https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.5.207/pdf.worker.js'

具体使用借鉴的是网上代码,原文链接我暂时没找到,如果看到可以告诉我我附上转载链接。

      <!--界面-->
      <div class="preview-pdf">
        <div :style="`margin:0 auto;width:${pdfWidth};`">
          <canvas
            v-for="page in pdfPages"
            :id="'pdfCanvas' + page"
            :key="page"
          />
        </div>
      </div>

具体调用方法

const pdfPages = ref<any>([])
const pdfWidth = ref('')
const pdfDoc = ref<any>('')
const pdfScale = 1.0
const pdfSrc = ref('')

const loadFile = (url) => {
  const CMAP_URL = 'https://unpkg.com/pdfjs-dist@2.5.207/cmaps/'
  const loadingTask = PDFJS.getDocument({
    url: url,
    withCredentials: false, // 携带凭证
    cMapUrl: CMAP_URL,
    cMapPacked: true,
    httpHeaders: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, OPTIONS',
      'Access-Control-Expose-Headers': 'Accept-Ranges, Content-Encoding, Content-Length, Content-Range'
    }
  })
  loadingTask.promise.then(pdf => {
    pdfDoc.value = pdf as any
    pdfPages.value = pdf.numPages
    nextTick(() => {
      renderPage(1)
    })
  })
}
const renderPage = (num) => {
  pdfDoc.value.getPage(num).then(page => {
    const canvas = document.getElementById('pdfCanvas' + num) as any
    const ctx = canvas.getContext('2d')
    const dpr = window.devicePixelRatio || 1
    const bsr =
          ctx.webkitBackingStorePixelRatio ||
          ctx.mozBackingStorePixelRatio ||
          ctx.msBackingStorePixelRatio ||
          ctx.oBackingStorePixelRatio ||
          ctx.backingStorePixelRatio ||
          1
    const ratio = dpr / bsr
    const viewport = page.getViewport({ scale: pdfScale })
    canvas.width = viewport.width * ratio
    canvas.height = viewport.height * ratio

    canvas.style.width = viewport.width + 'px'

    pdfWidth.value = viewport.width + 'px'

    canvas.style.height = viewport.height + 'px'

    ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
    // 将 PDF 页面渲染到 canvas 上下文中
    const renderContext = {
      canvasContext: ctx,
      viewport: viewport
    }
    page.render(renderContext)
    if (pdfPages.value > num) {
      renderPage(num + 1)
    }
  })
}

使用

loadFile(pdf后缀文件地址)

excel

使用的是xlsx.js,0.18.5版本,界面上用了elment-plus2.1.5,与我typeScript版本4.5.2兼容的版本,不然打包会报一些ts类型找不到的错误。也可以自己封装一个table组件使用,因为我的项目对于excel的效果要求不是很高,所以没有选择费时间自己去封装,而是引入特定的el-table。

      <el-table :data="tableData" style="width: 100%">
        <el-table-column
          v-for="(value,key,index) in tableData[2]"
          :key="index"
          :prop="key+''"
          :label="key+''"
        />
      </el-table>

主要方法

import * as XLSX from 'xlsx'

const tableData = ref([])
const workbook = ref({} as any)
const getTable = (sheetName:string) => {
  const worksheet = workbook.value.Sheets[sheetName]
  tableData.value = XLSX.utils.sheet_to_json(worksheet)
  console.log(tableData.value)
}
const getExcel = (url) => {
  const xhr = new XMLHttpRequest()
  xhr.open('get', url, true)
  xhr.responseType = 'arraybuffer'
  xhr.onload = function(e) {
    if (xhr.status === 200) {
      const data = new Uint8Array(xhr.response)
      const res = XLSX.read(data, { type: 'array' })
      const sheetNames = res.SheetNames // 工作表名称集合
      workbook.value = res
      console.log(workbook.value)
      getTable(sheetNames[0])
    }
  }
  xhr.send()
}

调用

getExcel(文件地址)

word

采用mammoth,安装的是1.4.21版本 界面

<div id="wordView" v-html="vHtml" />

方法,这里注意引入的是mammoth.browser,算是一个坑吧

import * as mammoth from 'mammoth/mammoth.browser'
const getWord = (event) => {
  const xhr = new XMLHttpRequest()
  xhr.open('get', event, true)
  xhr.responseType = 'arraybuffer'
  xhr.onload = function() {
    if (xhr.status === 200) {
      mammoth
        .convertToHtml({ arrayBuffer: new Uint8Array(xhr.response) })
        .then((resultObject) => {
          nextTick(() => {
            vHtml.value = resultObject.value
          })
        })
    }
  }
  xhr.send()
}

调用

getWord(word地址)