vue 预览docx、pdf、xls、xlsx文件

office官方提供了office文件的预览,但是需要有域名与公网能访问到才行
官网预览方式,src后加你的文件路径

https://view.officeapps.live.com/op/view.aspx?src=
官网

内网预览插件(代码在文末)

pdf预览插件(vue-pdf)

安装

npm install --save vue-pdf

使用

在需要使用的文件中引入即可
import pdf from “vue-pdf”

样例
在这里插入图片描述

docx预览插件(mammoth)

该插件主要是把源文档转成了html,不支持doc文件
安装

npm install --save mammoth

使用

在需要使用的文件中引入即可
import mammoth from ‘mammoth’

xls、xlsx文件插件(xlsx)

安装

npm install xlsx -s

使用

同上,引入即可
import XLSX from “xlsx”

组件最终代码贴上

<template>
  <div>
    <el-dialog :visible="visible" :close-on-press-escape="false" :close-on-click-modal="false" append-to-body
               @close="handleClose" width="800px" :fullscreen="fullscreen">
      <template slot="title">
        <div class="dialog-title ellipsis">
          <div style="width: calc(100% - 20px);display: inline;">
            文件预览({{ file.name }})
          </div>
          <div class="full-screen__menu" @click="fullscreen? fullscreen=false: fullscreen=true">
            <i class="el-icon-full-screen"></i>
          </div>
        </div>
      </template>
      <div>
        <!-- pdf预览 -->
        <div v-if="fileType===1">
          <div v-if="pdfData.pageCount>1">
            <el-button type="primary" size="mini" @click="changePdfPage(0)" icon="el-icon-arrow-left"></el-button>
            <span style="font-size: 14px;font-weight: 550;margin: 0 10px">{{ pdfData.currentPage }} / {{
                pdfData.pageCount
              }}</span>
            <el-button type="primary" size="mini" @click="changePdfPage(1)" icon="el-icon-arrow-right"></el-button>
          </div>
          <div
            :style="{height:fullscreen?(clientHeight-200)+'px':(clientHeight-400>800?800:clientHeight-400)+'px'}"
            style="margin-top: 5px;border: 1px solid #a0a0a0;overflow:auto;">
            <pdf
              :src="pdfData.src"
              :page="pdfData.currentPage"
              @num-pages="pdfData.pageCount=$event"
              @page-loaded="pdfData.currentPage=$event"
            ></pdf>
          </div>
        </div>
        <!-- word文档预览 -->
        <div v-if="fileType===2">
          <div
            :style="{height:fullscreen?(clientHeight-200)+'px':(clientHeight-400>800?800:clientHeight-400)+'px'}"
            style="margin-top: 5px;border: 1px solid #a0a0a0;overflow: auto">
            <div v-html="docHtml" style="padding: 10px 15px"></div>
          </div>
        </div>
        <!-- Excel文档预览 -->
        <div v-if="fileType===3">
          <div class="tab">
            <el-radio-group size="small" v-model="excel.sheetNameActive" @change="getSheetNameTable">
              <el-radio-button v-for="(item,index) in excel.sheetNames" :key="index" :label="item"></el-radio-button>
            </el-radio-group>
          </div>
          <div
            :style="{height:fullscreen?(clientHeight-200)+'px':(clientHeight-400>800?800:clientHeight-400)+'px'}"
            style="margin-top: 5px;border: 1px solid #a0a0a0;overflow:auto;">
            <div v-html="excel.SheetActiveTable" style="padding: 10px 15px"></div>
          </div>
        </div>
        <div v-if="!fileType" style="line-height: 50px;text-align: center;font-size: 16px">
          文件格式不支持,仅支持pdf,docx,xlsx,xls文件预览
        </div>
      </div>
      <div style="text-align: right;margin-top: 5px">
        <el-button size="small" @click="handleClose" class="raise">关闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import XLSX from "xlsx"
import pdf from "vue-pdf"
import mammoth from 'mammoth'

export default {
  name: "officePreview",
  props: {
    visible: {
      type: Boolean,
      default: false
    },
    // file:{name:'',url:''}
    file: {
      type: Object,
      default: () => {
        return {}
      }
    },
    // 弹窗高度
    clientHeight: {
      type: Number,
      default: 600
    },
    // 基础链接
    baseURL: {
      type: String,
      default: undefined
    }
  },
  data() {
    return {
      // 全屏
      fullscreen: false,
      // 文件类型
      fileType: 1,
      // pdf数据
      pdfData: {
        // 当前页
        currentPage: 1,
        // pdf文件总页数
        pageCount: 0,
        //
        src: ""
      },
      docHtml: "",
      // 空文件提示信息
      emptyTips: '暂无内容',
      // Excel文档数据
      excel: {
        // 数据
        workbook: {},
        // 表名称集合
        sheetNames: [],
        // 激活项
        sheetNameActive: "",
        // 当前激活表格
        SheetActiveTable: ""
      }
    }
  },
  methods: {
    handleClose() {
      this.$emit("update:visible", false)
    },
    /**
     * 切换pdf显示页
     * @param command
     */
    changePdfPage(command) {
      if (command === 0) {
        if (this.pdfData.currentPage > 1) {
          this.pdfData.currentPage--
        }
      } else if (command === 1) {
        if (this.pdfData.currentPage < this.pdfData.pageCount) {
          this.pdfData.currentPage++
        }
      }
    },
    /**
     * 获取文件类型
     * @return {null|number}
     */
    getFileType() {
      if (!this.file) {
        return null
      }
      let fileName = this.file.name.lastIndexOf(".");//取到文件名开始到最后一个点的长度
      let fileNameLength = this.file.name.length;//取到文件名长度
      let fileFormat = this.file.name.substring(fileName + 1, fileNameLength);//截
      console.log(fileFormat)
      if (fileFormat.toLowerCase() === "pdf") {
        return 1
      } else if (fileFormat.toLowerCase() === "docx") {
        return 2
      } else if (fileFormat.toLowerCase() === "xlsx" || fileFormat.toLowerCase() === "xls") {
        return 3
      }
      return null
    },
    /**
     * pdf预览
     */
    initPdf() {
      // this.pdfData.src = pdf.createLoadingTask(this.$baseURL + this.file.url)
      try {
        // 加载
        let _this = this
        const xhr = new XMLHttpRequest();
        xhr.open('get', this.baseURL + this.file.url, true);
        xhr.responseType = 'blob';
        xhr.onload = function () {
          if (xhr.status === 200) {
            _this.pdfData.src = _this.getObjectURL(xhr.response)
          } else if (xhr.status === 404) {
            _this.$error({message: "文件不存在"})
          } else {
            _this.$error({message: "读取服务器文档异常"})
          }
        }
        xhr.onerror = function () {
          _this.$error({message: "访问服务器异常,请检查访问链接是否正常"})
        }
        xhr.send();
      } catch (e) {
        console.log(e)
      }
    },
    /**
     * 将返回的流数据转换为url
     * @param file 文件流
     */
    getObjectURL(file) {
      let url = null;
      if (window.createObjectURL !== undefined) { // basic
        url = window.createObjectURL(file);
      } else if (window.webkitURL !== undefined) { // webkit or chrome
        try {
          url = window.webkitURL.createObjectURL(file);
        } catch (error) {

        }
      } else if (window.URL !== undefined) { // mozilla(firefox)
        try {
          url = window.URL.createObjectURL(file);
        } catch (error) {
          console.log(error)
        }
      }
      return url;
    },
    /**
     * docx文件预览
     */
    initDocPreview() {
      // 请求文件流
      try {
        let _this = this
        const xhr = new XMLHttpRequest();
        xhr.open('get', this.baseURL + this.file.url, true);
        xhr.responseType = 'arraybuffer';
        xhr.onload = function () {
          if (xhr.status === 200) {
            mammoth.convertToHtml({arrayBuffer: new Uint8Array(xhr.response)}).then(function (resultObject) {
              _this.docHtml = resultObject.value
            })
          } else if (xhr.status === 404) {
            _this.$error({message: "文件不存在"})
          } else {
            _this.$error({message: "读取服务器文档异常"})
          }
        }
        xhr.onerror = function () {
          _this.$error({message: "访问服务器异常,请检查访问链接是否正常"})
        }
        xhr.send();
      } catch (e) {
        this.docHtml = '<h1 style="text-align: center">' + this.emptyTips + '</h1>'
      }
    },
    /**
     * 表格数据预览
     */
    initExcelPreview() {
      try {
        let xhr = new XMLHttpRequest()
        xhr.open('get', this.baseURL + this.file.url, true)
        xhr.responseType = 'arraybuffer'
        const _this = this
        xhr.onload = function (e) {
          if (xhr.status === 200) {
            const data = new Uint8Array(xhr.response)
            const workbook = XLSX.read(data, {type: 'array'})
            const sheetNames = workbook.SheetNames // 工作表名称集合
            _this.excel.workbook = workbook
            _this.excel.sheetNames = sheetNames
            _this.excel.sheetNameActive = sheetNames[0]
            _this.getSheetNameTable(sheetNames[0])
          } else if (xhr.status === 404) {
            _this.$error({message: "文件不存在"})
          } else {
            _this.$error({message: "读取服务器文档异常"})
          }
        }
        xhr.onerror = function () {
          _this.$error({message: "访问服务器异常,请检查访问链接是否正常"})
        }
        xhr.send()
      } catch (e) {
        console.log(e)
      }

    },
    /**
     * 根据工作表名称获取数据
     * @param sheetName
     */
    getSheetNameTable(sheetName) {
      try {
        // 获取当前工作表的数据
        const worksheet = this.excel.workbook.Sheets[sheetName]
        // 转换为数据  1.json数据有些问题,2.如果是html那么样式需修改
        let htmlData = XLSX.utils.sheet_to_html(worksheet, {header: '', footer: ''})
        htmlData = htmlData === '' ? htmlData : htmlData.replace(/<table/, '<table class="default-table" border="1px solid #ccc" cellpadding="0" cellspacing="0"')
        // 第一行进行改颜色
        htmlData = htmlData === '' ? htmlData : htmlData.replace(/<tr/, '<tr style="background:#b4c9e8"')
        this.excel.SheetActiveTable = htmlData
      } catch (e) {
        // 如果工作表没有数据则到这里来处理
        this.excel.SheetActiveTable = '<h4 style="text-align: center">' + this.emptyTips + '</h4>'
      }
    },
  },
  created() {
    this.fileType = this.getFileType()
    if (this.fileType === 1) {
      this.initPdf()
    }
    if (this.fileType === 2) {
      this.initDocPreview()
    }
    if (this.fileType === 3) {
      this.initExcelPreview()
    }
  },
  components: {
    pdf
  }
}
</script>

<style scoped>
.dialog-title {
  text-align: center;
  display: flex;
  font-size: 18px;
  width: calc(100% - 30px);
}

.full-screen__menu {
  font-size: 16px;
  display: inline;
}

.full-screen__menu:hover {
  font-size: 16px;
  color: #2D8CF0;
}
</style>
<style>

table.default-table {
  /* -moz-border-radius: 5px;
  -webkit-border-radius:5px;
  border-radius:5px; */
  width: 100%;
  border: solid #333;
  border-width: 1px 0px 0px 1px;
  font-size: 16px;
  border-collapse: collapse;
  border-spacing: 0;
}

table.default-table tbody tr {
  height: 20px;
  line-height: 20px;
  white-space: nowrap;
}

table.default-table tbody tr:hover {
  background-color: #eee;
}

table.default-table tbody tr th, table.default-table tbody tr td {
  padding: 3px 5px;
  text-align: left;
  /* border: 1px solid #ddd; */
  border: solid #333;
  border-width: 0px 1px 1px 0px;
  white-space: nowrap;
}

table.default-table tbody tr th {
  font-weight: bold;
  text-align: center;
}

table.default-table tbody tr td a:hover {
  color: #0080c0;
}
</style>

组件使用

将组件导入要使用的文件中即可

import officePreview from "../../../components/officePreview";
components: {
	officePreview
}
<office-preview :visible.sync="previewVisible" v-if="previewVisible" :client-height="clientHeight"
                    :file="previewFile" :base-u-r-l="officeURL"></office-preview>
Logo

前往低代码交流专区

更多推荐