随笔 - 19  文章 - 0  评论 - 1  阅读 - 8753

vue-pdf,实现pdf文件在线预览,放大缩小,下一页上一页,打印,禁止页面鼠标右击,禁用F12

一、安装

  npm install --save vue-pdf

二、pdf标签使用

  1.基础用法(显示一页)

<template>
    <div>
      <pdf ref="pdf" :src="url"></pdf>
    </div>
</template>
复制代码
<script>
import pdf from 'vue-pdf'
export default {
  components:{pdf},
  data(){
      return {
          url:"http://文件路径地址",
      }
  }
</script>
复制代码

  2.显示多页

  这时候我们可以通过滑动预览pdf的内容, 但是这种方式是一下子把pdf的内容都加载出来, 页数一多, 浏览器直接卡在加载的状态, 体验感太差,所以我们可以考虑按页加载

复制代码
<template>
  <div>
    <pdf
      ref="pdf"
      v-for="i in numPages" 
      :key="i"  
      :src="url" 
      :page="i"
      ></pdf>
  </div>
</template>
复制代码
复制代码
<script>
import pdf from 'vue-pdf'
export default {
  components:{
      pdf
  },
  data(){
      return {
          url:"http://文件路径地址",
          numPages: null, // pdf 总页数
      }
  },
  mounted() {
      this.getNumPages()
  },
  methods: {
    // 计算pdf页码总数
    getNumPages() {
      let loadingTask = pdf.createLoadingTask(this.url)
      loadingTask.promise.then(pdf => {
        this.numPages = pdf.numPages
      }).catch(err => {
        console.error('pdf 加载失败', err);
      })
    },
  }
</script>
复制代码

  3.分页预览

复制代码
<template>
  <div>
    <el-button-group>
      <el-button type="primary" icon="el-icon-arrow-left" size="mini" @click="prePage">上一页</el-button>
      <el-button type="primary" size="mini" @click="nextPage">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
    </el-button-group>
    <div style="marginTop: 10px; color: #409EFF">{{ pageNum }} / {{ pageTotalNum }}</div>
    <pdf
      :page="pageNum"
      :src="url"
      @progress="loadedRatio = $event"
      @num-pages="pageTotalNum=$event" 
      ></pdf>
  </div>
</template>
复制代码
复制代码
<script>
import pdf from 'vue-pdf'
export default {
  name: 'Pdf',
  components: {
    pdf,
  },
  data() {
    return {
      url: 'http://文件路径地址',
      pageNum: 1,//文件页码
      pageTotalNum: 1, //总页数
      loadedRatio: 0, //当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了
    }
  },
  created: {
  // 有时候pdf文件地址会出现跨域的情况,这里最好处理一下
  this.src = pdf.createLoadingTask(this.src)
  },
  methods: {
    // 上一页
    prePage() {
      let page = this.pageNum
      page = page > 1 ? page - 1 : this.pageTotalNum
      this.pageNum = page
    },
    // 下一页
    nextPage() {
      let page = this.pageNum
      page = page < this.pageTotalNum ? page + 1 : 1
      this.pageNum = page
    }
  }
}
</script>
复制代码

 

参数介绍:

  • page: 当前显示的页数,比如第一页page=1
  • rotate : 旋转角度,比如0就是不旋转,+90,-90 就是水平旋转。
  • progress :当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了。
  • page-loaded :页面加载成功的回调函数,不咋能用到。
  • num-pages :总页数
  • error :加载错误的回调
  • link-clicked:单机pdf内的链接会触发。

其他:

  • print 这个是打印函数。 注意:谷歌浏览器会出现乱码,这个和字体有关系。

 三、完整项目示例

复制代码
<template>
  <div class="app-container">
    <!-- 文件预览 -->
    <el-dialog
      :close-on-click-modal="false"
      title="文件预览"
      :visible.sync="dialogVisible"
      append-to-body
      fullscreen
      class="pdf_dialog"
      @close="closePDF"
    >
      <div class="pdf_fixed_bottom">
        <el-input-number
          class="mr10"
          controls-position="right"
          v-model="jumpNum"
          :min="1"
          :max="pdfpageTotalNum"
          :step="1"
          step-strictly
          label="请输入页码"
          size="mini"
        >
        </el-input-number>
        <el-button
          type="primary"
          @click="jumpPage"
          size="mini"
          class="pdf-btn-size"
        >
          跳转
        </el-button>
        <el-button type="primary" @click="preClockwise" size="mini">
          <img src="@/assets/image/7.png" /> //右旋转
        </el-button>
        <el-button type="primary" @click="preAntieClockwise" size="mini">
          <img src="@/assets/image/8.png" /> //左旋转
        </el-button>
        <el-button type="primary" @click="prePage" size="mini">
          <img src="@/assets/image/2.png" /> //上一页
        </el-button>
        <el-button type="primary" @click="nextPage" size="mini">
          <img src="@/assets/image/3.png" /> //下一页
        </el-button>
        <el-button
          type="primary"
          :class="{ select: idx == 0 }"
          @touchstart="idx = 0"
          @touchend="idx = -1"
          @click="scaleD"
          size="mini"
        >
          <img src="@/assets/image/5.png" /> //放大
        </el-button>
        <el-button
          type="primary"
          :class="{ select: idx == 1 }"
          @touchstart="idx = 1"
          @touchend="idx = -1"
          @click="scaleX"
          size="mini"
        >
          <img src="@/assets/image/6.png" /> //缩小
        </el-button>
        <el-button
          type="primary"
          @click="print"
          size="mini"
          class="pdf-btn-size"
        >
          <img src="@/assets/image/9.png" /> //打印
        </el-button>
      </div>
      <div class="page pdf_fixed_top">
        当前第{{ pdfpageNum }}页/共{{ pdfpageTotalNum }}页
      </div>
      <div class="pdf_transform">
        <pdf
          ref="pdf"
          :src="pdfurl"
          :page="pdfpageNum"
          :rotate="pdfpageRotate"
          @progress="pdfloadedRatio = $event"
          @page-loaded="pageLoaded($event)"
          @num-pages="pdfpageTotalNum = $event"
          @error="pdfError($event)"
          @link-clicked="pdfpage = $event"
          v-loading="dialogloading"
        >
        </pdf>
      </div>
    </el-dialog>
  </div>
</template>
复制代码
复制代码
<script>
import { getToken } from "@/utils/auth";
import { downloadNew } from "@/utils/ruoyi";
import { messagePrompt } from "@/utils/message"; //提示语集合
import { parameterPrompt } from "@/utils/parameter"; //固定参数集合
import pdf from "@/vue-pdf";
import Watermark from "@/utils/watermark";
export default {
  name: "test",
  components: {
    pdf,
  },
  data() {
    return {
      // pdf预览
      dialogloading: false,
      dialogVisible: false,
      pdfurl: " ",
      pdfpageNum: 1,
      pdfpageTotalNum: 1,
      pdfpageRotate: 0,
      jumpNum: 0,
      // 加载进度
      pdfloadedRatio: 0,
      pdfcurPageNum: 0,
      scale: 1, //放大系数
      idx: -1,
    };
  },
  created() {
    this.stopF5Refresh();
  },
  methods: {
    /** PDF预览 */
    // 预览pdf弹窗
    openDialogVisible(url) {
      var date = new Date();
      var year = date.getFullYear();
      var month = date.getMonth() + 1;
      var day = date.getDate();
      if (month < 10) {
        month = "0" + month;
      }
      if (day < 10) {
        day = "0" + day;
      }
      var nowDate = year + "-" + month + "-" + day;
      var name = "aaa";
        this.pdfurl = url;
        Watermark.set(name + nowDate); //水印格式:登录人+年月日
        this.dialogloading = true;
        this.dialogVisible = true;
    },
    // 关闭pdf
    closePDF() {
      Watermark.set("");
      this.dialogVisible = false;
      this.pdfpageNum = 1;
      this.pdfloadedRatio = 0;
      this.pdfpageRotate = 0;
      this.scale = 1;
      this.idx = -1;
      this.pdfurl = null;
      this.$refs.pdf.$el.style.transform =
        "scale(" + this.scale + "," + this.scale + ")";
      this.$refs.pdf.$el.style.transformOrigin = "0% 0%";
    },
    //放大
    scaleD() {
      this.scale += 0.1;
      this.$refs.pdf.$el.style.transform =
        "scale(" + this.scale + "," + this.scale + ")";
      this.$refs.pdf.$el.style.transformOrigin = "0% 0%";
    },

    //缩小
    scaleX() {
      this.scale += -0.1;
      this.$refs.pdf.$el.style.transform =
        "scale(" + this.scale + "," + this.scale + ")";
      this.$refs.pdf.$el.style.transformOrigin = "0% 0%";
    },
    //顺时针
    preClockwise() {
      this.pdfpageRotate = this.pdfpageRotate + 90;
    },
    //逆时针
    preAntieClockwise() {
      this.pdfpageRotate = this.pdfpageRotate - 90;
    },
    // 上一页函数,
    prePage() {
      var page = this.pdfpageNum;
      page = page > 1 ? page - 1 : this.pdfpageTotalNum;
      this.pdfpageNum = page;
    },
    // 下一页函数
    nextPage() {
      var page = this.pdfpageNum;
      page = page < this.pdfpageTotalNum ? page + 1 : 1;
      this.pdfpageNum = page;
    },
    //跳转
    jumpPage(e) {
      this.pdfpageNum = this.jumpNum;
    }, 
    //打印
    print() {
      this.$refs.pdf.print();
    },
    // 页面加载回调函数,其中e为当前页数
    pageLoaded(e) {
      this.pdfcurPageNum = e;
      if (this.pdfloadedRatio === 1) {
        this.$nextTick(() => {
          setTimeout(() => {
            this.dialogloading = false;
          }, 500);
        });
      }
    },

    // 其他的一些回调函数。
    pdfError(error) {
      console.error(error);
    },

    /* 禁止一系列查看的快捷键 */
    stopF5Refresh() {
      document.onkeydown = function (e) {
        var evt = window.event || e;
        var code = evt.keyCode || evt.which;
        //屏蔽F1---F12
        if (code > 111 && code < 124) {
          if (evt.preventDefault) {
            evt.preventDefault();
          } else {
            evt.keyCode = 0;
            evt.returnValue = false;
          }
        }
        //禁止ctrl+s
        if (e.ctrlKey && e.keyCode == 83) {
          return false;
        }
      };
      //禁止鼠标右键菜单
      document.oncontextmenu = function (e) {
        return false;
      };

      //阻止后退的所有动作,包括 键盘、鼠标手势等产生的后退动作。
      history.pushState(null, null, window.location.href);
      window.addEventListener("popstate", function () {
        history.pushState(null, null, window.location.href);
      });
    },
  },
};
</script>
<style lang="scss">
.pdf_dialog {
  .el-dialog__header {
    position: fixed !important;
    width: 100% !important;
    z-index: 999 !important;
    padding-bottom: 14px !important;
    background: #fff !important;
  }
  .el-dialog.is-fullscreen {
    background: #525659 !important;
  }
  .el-dialog__body {
    margin-top: 60px !important;
    height: 100% !important;
    padding: 20px !important;
  }
}
canvas {
  margin-bottom: 40px !important;
}
</style> 
复制代码

 

 

四、更多内容参考 

Vue PDF文件预览vue-pdf 
npm vue-pdf

 

 
 
posted on   阿宇爱吃鱼  阅读(707)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示