在vue中对pdf进行操作,如:预览、下载、打印等功能

在vue项目中,有的功能需要对pdf进行操作,比如:预览、下载、打印等,但是没有组件库有pdf的插件,需要安装下载专门的pdf插件,这里对pdf操作做了整合,分享给大家。

示例使用的是vue-pdf组件库,如果大家有更好的插件可以进行交流学习~

话不多说,上代码!!!(vue基础的代码就不过多展示了)

一、安装插件

npm i vue-pdf

插件的github地址: https://github.com/FranckFreiburger/vue-pdf

二、在公共组件库新建PdfView文件夹,这里放封装好的组件,代码如下

<template>
  <div class="pdfView">
    <div class="show">
    <!--分页显示-->
      <pdf
        ref="pdf"
        :src="pdfUrl"
        :page="pageNum"
        :rotate="pageRotate"
        @password="password"
        @progress="loadedRatio = $event"
        @loaded="onLoadSuccess"
        @page-loaded="pageLoaded($event)"
        @num-pages="pageTotalNum = $event"
        @error="pdfError($event)"
        @link-clicked="page = $event"
      >
      </pdf>
      <!--整页显示-->
      <!-- <pdf
        v-loading="loading"
        element-loading-text="拼命加载中"
        element-loading-spinner="el-icon-loading"
        element-loading-background="rgba(0, 0, 0, 0.8)"
        v-for="i in numPages"
        :key="i"
        :src="pdfUrl"
        :page="i"
        @error="pdfError($event)"
        ref="pdf"
      ></pdf> -->
    </div>

    <div class="pdf_footer">
      <div class="info">
        <div>当前页数/总页数:{{ pageNum }}/{{ pageTotalNum }}</div>
        <!-- <div>进度:{{ loadedRatio }}</div> -->
        <!-- <div>页面加载成功: {{ curPageNum }}</div> -->
      </div>
      <div class="operate">
        <el-button-group>
            <el-button type="primary" icon="el-icon-arrow-left" style="border-radius: 30px 0 0 30px" @click.stop="prePage">上一页</el-button>
            <el-button type="primary" @click.stop="nextPage" style="border-radius: 0 30px 30px 0">下一页<i class="el-icon-arrow-right el-icon&#45;&#45;right"></i></el-button>
          </el-button-group>
        <el-button-group>
          <el-button type="primary" style="border-radius: 30px 0 0 30px" @click="scaleD">放大</el-button>
          <el-button type="primary" style="border-radius: 0 30px 30px 0" @click="scaleX">缩小</el-button>
        </el-button-group>
        <!-- <el-button type="primary" @click="fileDownload(pdfUrl, 'pdf文件')">
          下载
          <i class="el-icon-download"></i>
        </el-button> -->
      </div>
    </div>
  </div>
</template>

<script>
import pdf from "vue-pdf";
export default {
  name: "vue_pdf_preview",
  props: {
    // 当前pdf路径
    pdfUrl: {
      type: String,
      default: "",
    },
  },
  components: {
    pdf,
  },
  data() {
    return {
      // 总页数
      pageTotalNum: 1,
      // 当前页数
      pageNum: 1,
      // 加载进度
      loadedRatio: 0,
      // 页面加载完成
      curPageNum: 0,
      // 放大系数 默认百分百
      scale: 100,
      // 旋转角度 ‘90’的倍数才有效
      pageRotate: 0,
      // 单击内部链接时触发 (目前我没有遇到使用场景)
      page: 0,
      // 当前页数
      numPages: 1,
      // 预览路径
      localUrl: '',
      loading: true
    };
  },
  watch: {
    pdfUrl: {
      handler(newVal,oldVal) {
        this.localUrl = "";
        this.localUrl = newVal;
        let loadingTask = pdf.createLoadingTask(this.localUrl);
        loadingTask.promise.then(pdf => {
          this.numPages = pdf.numPages;
          this.loading = false;
          console.log('this.numPages', this.numPages)
        }).catch((err) => {
          console.error('pdf加载失败', err)
        })
      },
      immediate: true
    }
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {
    onLoadSuccess(pdf) {
      // PDF加载成功后,可以将初始页码设置为第一页
      this.pageNum = 1;
    },
    //下载PDF
    fileDownload(data, fileName) {
      let blob = new Blob([data], {
        //type类型后端返回来的数据中会有,根据自己实际进行修改
        type: "application/pdf",
      });
      let filename = fileName || "pdf.pdf";
      if (typeof window.navigator.msSaveBlob !== "undefined") {
        window.navigator.msSaveBlob(blob, filename);
      } else {
        var blobURL = URL.createObjectURL(blob);
        // 创建隐藏<a>标签进行下载
        var tempLink = document.createElement("a");
        tempLink.style.display = "none";
        tempLink.href = blobURL;
        tempLink.setAttribute("download", filename);
        if (typeof tempLink.download === "undefined") {
          tempLink.setAttribute("target", "_blank");
        }
        document.body.appendChild(tempLink);
        tempLink.click();
        document.body.removeChild(tempLink);
        window.URL.revokeObjectURL(blobURL);
      }
    },
    //打印
    pdfPrintAll() {
      this.$refs.pdf.print();
    },
    //放大
    scaleD() {
      this.scale += 5;
      this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
    },

    //缩小
    scaleX() {
      // scale 是百分百展示 不建议缩放
      if (this.scale == 100) {
        return;
      }
      this.scale += -5;
      console.log(parseInt(this.scale) + "%");
      this.$refs.pdf.$el.style.width = parseInt(this.scale) + "%";
    },
    // 切换上一页
    prePage() {
      var p = this.pageNum;
      p = p > 1 ? p - 1 : this.pageTotalNum;
      this.pageNum = p;
    },
    // 切换下一页
    nextPage() {
      var p = this.pageNum;
      p = p < this.pageTotalNum ? p + 1 : 1;
      this.pageNum = p;
    },
    // pdf 有密码 则需要输入秘密
    password(updatePassword, reason) {
      updatePassword(prompt('password is "test"'));
      console.log("...reason...");
      console.log(reason);
      console.log("...reason...");
    },
    // 页面加载成功  当前页数
    pageLoaded(e) {
      console.log("pageLoaded",e);
      this.$emit("current", e);
      this.curPageNum = e;
    },
    // 异常监听
    pdfError(error) {
      console.error('异常监听', error);
    },
    // getNumPages() {
    //   let loadingTask = pdf.createLoadingTask(this.pdfUrl);
    //   loadingTask.promise.then(pdf => {
    //     this.numPages = pdf.numPages;
    //     console.log('this.numPages', this.numPages)
    //   }).catch((err) => {
    //     console.error('pdf加载失败')
    //   })
    // },
  },
};
</script>

<style lang="scss" scoped>
.pdfView {
  padding: 20px;
  .show {
    overflow: auto;
    margin: auto;
    max-width: 100%;
    //height: 80vh;
    max-height: 580px;
    border: 2px solid #eee;
    border-radius: 6px;
    background-color: #eeeeee;
    // 滚动条样式
    &::-webkit-scrollbar {
      width: 10px;
    }
    &::-webkit-scrollbar-thumb {
      background-color: #999;
      border-radius: 6px;
    }
    &::-webkit-scrollbar-track {
      background-color: transparent;
      border-radius: 6px;
    }
  }
  .pdf_footer {
    position: sticky;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 10px 0;
    background-color: rgba(255, 255, 255, 0.5);
    .info {
      display: flex;
      flex-wrap: wrap;
      justify-content: space-around;
      div {
        width: 30%;
      }
    }
    .operate {
      margin: 10px 0 0;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      div {
        // width: 80px;
        text-align: center;
        font-size: 15px;
      }
      .btn {
        cursor: pointer;
        margin: 5px 10px;
        width: 120px;
        border-radius: 10px;
        padding: 5px;
        color: #fff;
        background-color: #3dcbbc;
      }
    }
  }
}
</style>

这里给出了几种展示方式,有分页显示,有整页显示。按照项目需求可自行进行调整。

三、在页面你需要的地方引用

import PdfView from "@/components/PdfView";
import pdf from 'vue-pdf';
export default {
  components:{pdf},
  data(){
    return{
       pdf_img_url: null,//pdf文件路径
    }
  },
  methods:{
    downloadPDF(){
      let url=this.pdf_img_url
      let newTab = window.open(url, '_blank');
      // 新窗口加载完后打印
      newTab.onload = function() {
         newTab.focus();
         newTab.print();
      };
    },
    printPdf() {
      console.log('this???????',this.$refs.pdf);
      this.$refs.pdf.pdfPrintAll()
    },
  }
}
<el-dialog
      title="PDF文件预览"
      :visible.sync="PdfViewVisible"
      append-to-body
      lock-scroll
      width="50%"
      :before-close="handleClosePdf"
    >
      <el-button  @click="downloadPDF">下载</el-button>
      <i class="el-icon-printer" @click="printPdf" style="cursor: pointer;float: right;font-size: 25px;"></i>//这是打印事件
      <pdf-view :pdfUrl="pdf_img_url" ref="pdf" @load="onPDFLoaded"></pdf-view>
    </el-dialog>

我这里放在了dialog中使用,可以根据自己实际需要的场景来进行使用。

预览是在当前页面打开的,不需要打开浏览器新窗口。

打印也是在当前页面打开了打印的窗口,但是需要注意有乱码的情况产生,这时需要更改插件的源文件。如果你的项目没有要求当前页面还是新窗口打开,那可以直接使用window.print(),可以参考下载的方法,调出浏览器自带的打印、下载事件(这个比较成熟,可以直接用)。

四、运行示例

注意:pdf_img_url我这里是请求后端接口拿到的,就不展示那部分代码了。

温馨提示:关闭dialog框时,记得清除pdf文件路径,避免打开下一个时还加载的是当一个文件。

好啦,这次的分享就进行到这了。博主也是第一次使用这个插件,在不断学习中,如果有朋友发现问题可进行评论交流学习。勿喷勿喷!!!

  • 11
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Vue3实现在线预览PDF的方法有两种。方法一是使用vue-pdf-embed和pdfjs-dist插件,具体步骤如下: 1. 首先,安装vue-pdf-embed和pdfjs-dist插件的依赖,可以使用命令`pnpm install vue-pdf-embed pdfjs-dist`进行安装。 2. 安装完成后,在需要预览PDF的页面,引入vue-pdf-embed插件,可以使用`import pdf from 'vue-pdf-embed'`进行引入。 3. 然后,可以在页面使用vue-pdf-embed组件进行PDF预览。在组件,通过设置props来传递PDF文件的路径或链接。例如,可以在模板使用`<pdf :src="pdfUrl"></pdf>`来显示PDF文件。 4. 最后,确保pdfjs-dist插件也已经正确安装,并且在项目引入。可以使用`import 'pdfjs-dist/build/pdf.worker.entry'`来引入。这样就能够在Vue3项目实现在线预览PDF了。 另外,方法二是使用其他支持Vue3的插件来实现PDF预览,可以根据项目需求选择合适的插件。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Vue3预览打印PDF的两种方法](https://blog.csdn.net/qing_jian0119/article/details/128739730)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [vue3 实现预览pdf的几种方式(vue3-pdf, iframe流展示,vue-office/pdf)](https://blog.csdn.net/dj7858177/article/details/131822861)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值