• 前端实现docx、pdf格式文件在线预览


    介绍

    在业务中,如果遇到文档管理类的功能,会出现需要在线预览的业务需求,本文主要是通过第三方库来实现文档预览功能,并将其封装成preview组件

    docx

    docx的实现需要使用docx-preview插件

    安装

    npm i docx-preview
    

    使用

    创建一个容器标签

    <div ref="file" v-show="extend == 'docx'">div>
    

    引入并创建渲染函数

    import { renderAsync } from "docx-preview";
    renderDocx() {
          renderAsync(this.fileData, this.$refs.file, null, {
            className: "docx", //默认和文档样式类的类名/前缀
            inWrapper: true, //启用围绕文档内容呈现包装器
            ignoreWidth: false, //禁用页面的渲染宽度
            ignoreHeight: false, //禁用页面的渲染高度
            ignoreFonts: false, //禁用字体渲染
            breakPages: true, //在分页符上启用分页
            ignoreLastRenderedPageBreak: true, //在lastRenderedPageBreak元素上禁用分页
            experimental: false, //启用实验功能(制表符停止计算)
            trimXmlDeclaration: true, //如果为true,则在解析之前将从xml文档中删除xml声明
            useBase64URL: false, //如果为true,图像、字体等将转换为base 64 URL,否则使用URL.createObjectURL
            useMathMLPolyfill: false, //包括用于铬、边等的MathML多填充。
            showChanges: false, //启用文档更改的实验渲染(插入/删除)
            debug: false, //启用额外的日志记录
          });
        },
    

    PDF

    pdf的预览需要使用PDFJS这个插件,通过将文件流解析写到canvas上实现预览效果

    安装

    npm i pdfjs-dist
    

    引入和使用

    <canvas
      v-for="num in numPages"
      :key="num"
      :id="'canvas_' + num"
      class="canvas"
    >canvas>
    

    此处pdf的渲染数据this.fileData必须是一个ArrayBuffer格式的数据,如果请求的的数据是Blob格式必须要先使用Blob.arrayBuffer()转换

    async renderPdf(num = 1) {
          this.fileData.getPage(num).then(page => {
            // 设置canvas相关的属性
            const canvas = document.getElementById("canvas_" + num);
            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: this.pdfScale }); // 设置放缩比率
            canvas.width = viewport.width * ratio;
            canvas.height = viewport.height * ratio;
            canvas.style.width = viewport.width + "px";
            canvas.style.height = viewport.height + "px";
            ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
            const renderContext = {
              canvasContext: ctx,
              viewport: viewport,
            };
            // 数据渲染到canvas画布上
            page.render(renderContext);
            if (this.numPages > num) {
              setTimeout(() => {
                return this.renderPdf(num + 1);
              });
            }
          });
        },
    

    pdf的放大和缩小

    pdf文件渲染后如果不能调整大小会因为源文件的大小和文件内容,出现模糊的问题,所以进行缩放渲染是有必要的

    // pdf放大
    setPdfZoomin() {
      const max = 2;
      if (this.pdfScale >= max) {
        return;
      }
      this.pdfScale = this.pdfScale + 0.2;
      this.renderPdf();
    },
    // pdf缩小
    setPdfZoomout() {
      const min = 0.6;
      if (this.pdfScale <= min) {
        return;
      }
      this.pdfScale = this.pdfScale - 0.1;
      this.renderPdf();
    },
    

    多格式的文件渲染函数映射

    因为将多种文件渲染放在一个文件中,所以处理函数需要做映射处理,执行对应格式的文件渲染

    renderPreview(extend) {
        const handle = {
        docx: () => {
          this.extend = "docx";
          this.$nextTick(() => this.renderDocx());
        },
        pdf: () => {
          this.extend = "pdf";
          new Blob([this.fileData]).arrayBuffer().then(res => {
            PDFJS.getDocument(res).promise.then(pdfDoc => {
              this.numPages = pdfDoc.numPages; // pdf的总页数
              this.fileData = pdfDoc;
              this.$nextTick(() => this.renderPdf());
            });
          });
        },
        };
        this.isLoading = false;
        if (!Object.hasOwn(handle, extend)) {
        this.extendName = extend;
        return (this.extend = "other");
        }
        handle[extend]();
    },
    

    不支持的文件提示处理

    在这个文件中,目前只支持docx和pdf的预览,如果出现了不支持的文件,需要增加一个提示处理,告知用户
    例如如下的文件提示

    <div class="container" v-show="extend == 'other'">
      <a-alert
        :message="`不支持.${this.extendName}格式的在线预览,请下载后预览或转换为支持的格式`"
        description="支持docx, pdf格式的在线预览"
        type="info"
        show-icon
      />
    div>
    

    总结

    本文只是简单的总结了关于文件预览的纯前端实现和封装方式,对于业务的思路简单整理,如果是对于有更复杂的场景,还需要有更加具体的拆分和优化。


    __EOF__

  • 本文作者: chenSee
  • 本文链接: https://www.cnblogs.com/wanna2leo/p/16717991.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    三种中间件的刷盘(持久化)策略
    商城系统需求分析
    web安全之MySQL手工注入的原理讲解和实验分析
    上周热点回顾(4.1-4.7)
    node.js基础
    c++视觉处理----固定阈值操作:Threshold()函数,实时处理:二值化,反二值化,截断,设为零,反向设为零
    进程环境+进程终止
    代码随想录Day_55打卡
    【Python从入门到进阶】67、Pandas使用stack和pivot实现数据透视
    C++容器
  • 原文地址:https://www.cnblogs.com/wanna2leo/p/16717991.html