目录
  • 介绍
  • docx
    • 安装
    • 使用
  • PDF
    • 安装
    • 引入和使用
    • 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>

        总结

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

        声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。