pdfjs-dist 的工作原理:把获取到的 pbf 的文件的数据流, 利用 canvas转换成图片

turnjs 把多个元素做成翻书的特效

我接手了一个展示大屏的项目, 其中有一个地方,就是要以翻书的形式来预览 pdf文件
如图

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

首先 安装 psfjs-dist

npm install --save pdfjs-dist

turnjs 是jquery的项目, 所以, 我们要在vuejs中安装 jquery

vue中安装jquery的方法

npm install jquery --save
然后在 vue.config.js中配置

module.exports = {
  chainWebpack: config => {
    config.plugin('provide').use(webpack.ProvidePlugin, [{
      $: 'jquery',
      jquery: 'jquery',
      jQuery: 'jquery',
      'window.jQuery': 'jquery'
    }])
  }

下载trunjs

http://www.turnjs.com/ 官网下载
我写这个笔记的时候, 官网好像下载出错了,我找到了另一种下载的方法

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

把官网的示例随便打开了个, 找到 上图中的地址

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

这样也可以得到我们想要的 trunjs库

上面是安装, 下面我们开始使用

       <div class="body-content" style="height:850px;">
                      <v-touch @swipeleft="changeindexleft(1)" @swiperight="changeindexright(1)">
                      <div id="magazine1" style="height:850px;width:1200px;margin-left:0 !important;">
                        <!-- 这里的 magazine1  就是翻页组件的容器 -->
                      </div>
                      </v-touch>
                          <!-- 这里的 docview1 是用来存放 pdf转成图片时,所用到的 canvas 标签的-->
                      <div style="margin: 0 auto; text-align: center; display: none">
                        <div id="docView1" ref="docView1"></div>
                      </div>
                    </div>

代码部份

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

引入 jquery 和 turnjs

import $ from "jquery";
import * as PDFJS from "pdfjs-dist";
import turn from "../utils/lib/turn.js"
//初始化pdf插件
    /*
     ** @param fileUrl pdf有效的查看地址
     **				(1、线上地址(如:http://www.xxx.com)
     **				2、本地public地址(例如:/static/view.pdf))
     ** @param  pdfPicturePath1 pdf转化的图片地址-用于放大查看所有pdf图片
     */
    readPdf(fileUrl,index) {
    	//这个index 是我代码中要用的, 如果单独使用的话, 可以不要 index 这个参数
      let self = this;
        let loadingTask1 = PDFJS.getDocument(fileUrl);  //读取pdf文件
        console.log(loadingTask1, '-----------loadingTask');
        loadingTask1.promise
            .then(function (pdf) {
              if (pdf) {
                // pdf 总页数
                const pageNum = pdf.numPages;
                for (let i = 1; i <= pageNum; i++) {
                  // 生成每页 pdf 的 canvas
                  const canvas = document.createElement('canvas');
                  canvas.id = 'page'+index+'Num' + i;
                  canvas.className = 'h'+index;
                  // 将 canvas 添加到 dom 中,docView(存放canvas的div)
                  let docViewX = "docView"+index;
                  console.log(docViewX);
                  self.$refs[docViewX].append(canvas);
                  //getContext() 方法返回一个用于在画布上绘图的环境。
                  const context = canvas.getContext('2d');
                  self.openPage(pdf, i, context);
                }
                setTimeout(() => {
                  self.exportImg(self,index);
                }, 2000);
              }
            })
            .catch(function (reason) {
              console.error('Error: ' + reason);
            });
   
    },



//pdf转成canvas
    /*
     ** @param loading pdf生成图片时的加载状态
     ** @param scale 控制 canvas显示的大小
     */
    openPage(pdfFile, pageNumber, context) {
      let that = this;
      pdfFile.getPage(pageNumber).then(function (page) {
        // reference canvas via context
        let viewport = page.getViewport({scale:1});
        let scale =(847 / viewport.height).toFixed(2)  //这里根把自已的项目需求,宽高进行调整
        let viewport1 = page.getViewport({scale:scale});

        let canvas = context.canvas;
        canvas.width = viewport1.width;
        canvas.height = viewport1.height;
        canvas.style.width = '100%';
        canvas.style.height = '100%';

        let renderContext = {
          canvasContext: context,
          viewport: viewport1
        };
        page.render(renderContext);
        that.loading = false;
      });
      return;
    },



//canvas转成图片(可根据具体情况,进行图片转化显示)这里我把所有图片的base64存放在数组里面,方便放大查看,也可以直接把生成图片标签进行图片展示
    // 转图片
    exportImg(self,index) {
      //let canvaslist= document.querySelectorAll('canvas');
      let canvaslist = document.getElementsByClassName("h"+index);
      let pdfPicturePathX = "pdfPicturePath"+index;
      this[pdfPicturePathX] = [];
      //这里把所有的图片地址放入到 pdfPicturePath1 数组中去
      for (let i = 0; i < canvaslist.length; i++) {
        // let canvas = document.getElementById("pageNum" + (i + 1));
        // // 将 canvas 转成 base64 格式的图片
        // let base64ImgSrc = (canvas as any).toDataURL("image/png")
        // const img = document.createElement("img")
        // img.setAttribute('class', 'pdf-img');
        // img.src = base64ImgSrc
        // img.style.width = '100%';
        // // 将图片挂载到 dom 中
        // (self.$refs as any).docView.append(img);
        let canvasNode = document.getElementById('page'+index+'Num' + (i + 1));
        // 将 canvas 转成 base64 格式的图片
        if(canvasNode){
          this[pdfPicturePathX].push({page: i + 1, pic: canvasNode.toDataURL('image/png'), name: i + 1})
        }else {
          continue;
        }
        //console.log('--------------aaa-------------', this.pdfPicturePath1);
      }
	//到上面就是把pdf文件转成 base64格式的图片, 之后把它们存在 pdfPicturePath1的数组中

      this.$nextTick(()=>{
        if(index == 1){
          if($("#magazine1").children().length > 0){
            $("#magazine1").turn("destroy");
            $("#magazine1").children().remove();
          }
          let magazine1 = $("#magazine1");
          this[pdfPicturePathX].forEach(i=>{
            magazine1.append("<img src='"+i.pic+"'/>")
          });

          //setTimeout(()=>{

            $("#magazine1").turn({
              autoCenter: true,
              elevation: 50,
              acceleration: true,
              //direction:"rtl",
              // when: {
              //   turned: function() {
              //     //当前页
              //     // console.log("Current view: ", $(this).turn("view"));
              //     // //总页数
              //     // console.log(
              //     //     "#magazine has " + $("#magazine").turn("pages") + " pages"
              //     // );
              //     //$("#magazine").turn("hasPage", 10);
              //     //$("#magazine").turn("pages", 1);
              //   }
              // }
            })
          $("#magazine1").turn("center");
          $("#magazine1").turn("page");

          //console.log($("#magazine1").turn("pages"));
            $("#magazine1").bind("start",function(e,p,c){
              if(c == "tl"||c == 'tr'){
                e.preventDefault();
              }
            })
          //},1000
        }
    },


下面是我项目的一个完现代码

<template>
  <div id="index" ref="appRef">

    <div class="bg">
      <dv-loading v-show="loading">Loading...</dv-loading>
      <div v-show="!loading" class="host-body">
        <!--        第一行-->

        <div class="row1">
          <div class="title-wrapper">
            <img src="../assets/pic_rczs_title1.png">
            <fullscreen ref="fullscreen" style="float:right"></fullscreen>
          </div>
        </div>
        <!-- 第二行 -->
        <div class="row2">
          <div class="item_3">
            <div class="picwrapper" v-show="showfengmian1">
              <div class="initem" v-if="categoryslist[0]" @click="fengmianclick(1,0)">
                <img :src="categoryslist[0].more.thumbnail"/>
                <div class="intitle">{{categoryslist[0].name}}</div>
              </div>
              <div class="initem"  v-if="categoryslist[1]" @click="fengmianclick(1,1)">
                <img :src="categoryslist[1].more.thumbnail"/>
                <div class="intitle">{{categoryslist[1].name}}</div>
              </div>
            </div>

            <div class="detailwrapper" v-show="!showfengmian1">
              <div class="dtop">
                <img src="../assets/pic_qyzc_shrcxzsy.png"/>
              </div>
              <div class="btmwrapper">
                <div class="left">
                  <img src="../assets/icon_fanhui.png" @click="backtoshow(1)"/>
                </div>
                <div class="right">
                  <div class="content" v-show="!showpdf1">
                    <div class="listdetailwrapper">
                      <div class="listtop">
                        <multiselect v-model="value1"
                                     placeholder="请选择"
                                     open-direction="bottom"
                                     :show-labels="false"
                                     trackBy="id"
                                     label="name"
                                     @select="chooseSelect1"
                                     :options="selectoptions1">
                        </multiselect>
                      </div>
                      <div class="listwrapper">
                        <div @click="chooselist(1,index,item)" class="listitem" :class="selectItemIndex1 == index?'coloractive':''" v-for="(item,index) in selectList1" :key="item.id">{{item.name}}<span style="float: right" v-if="selectItemIndex1 == index"> 》</span></div>
                      </div>
                    </div>
                    <div class="detail" :style="{height:ispdf1?'':'100%'}">
                      <div v-if="!ispdf1" class="markdown-body editor" v-html="articleDetail1.post_content"></div>
                      <div class="img-wrapper" v-if="ispdf1" @click="pdfshowClick(1,articleDetail1.more.files)">
                        <img class="img1" src="../assets/pic_mrfm_wj@2x.png"/>
                      </div>
                    </div>
                  </div>
                  <div class="pdf-wrapper"  v-show="showpdf1">
                    <div class="body-content" style="height:850px;">
                      <v-touch @swipeleft="changeindexleft(1)" @swiperight="changeindexright(1)">
                      <div id="magazine1" style="height:850px;width:1200px;margin-left:0 !important;">

<!--                        <div v-for="(item, index) in pdfPicturePath1" :key="`test_${index}`">-->
<!--                          <div>-->
<!--                            <v-touch @swipeleft="changeindexleft(1)" @swiperight="changeindexright(1)">-->
<!--                            <img :src="item.pic" class="pdf_pic" />-->
<!--                            </v-touch>-->
<!--                          </div>-->
<!--                        </div>-->
                      </div>
                      </v-touch>
                      <div style="margin: 0 auto; text-align: center; display: none">
                        <div id="docView1" ref="docView1"></div>
                      </div>
                    </div>

                  </div>
                </div>
              </div>

            </div>
          </div>

          <div class="item_3">
            <div class="picwrapper" v-show="showfengmian2">
              <div class="initem" v-if="categoryslist[2]" @click="fengmianclick(2,2)">
                <img :src="categoryslist[2].more.thumbnail"/>
                <div class="intitle">{{categoryslist[2].name}}</div>
              </div>
              <div class="initem"  v-if="categoryslist[3]" @click="fengmianclick(2,3)">
                <img :src="categoryslist[3].more.thumbnail"/>
                <div class="intitle">{{categoryslist[3].name}}</div>
              </div>
            </div>

            <div class="detailwrapper" v-show="!showfengmian2">
              <div class="dtop">
                <img src="../assets/pic_qyzc_shrcxzsy.png"/>
              </div>
              <div class="btmwrapper">
                <div class="left">
                  <img src="../assets/icon_fanhui.png" @click="backtoshow(2)"/>
                </div>
                <div class="right">
                  <div class="content" v-show="!showpdf2">
                    <div class="listdetailwrapper">
                      <div class="listtop">
                        <multiselect v-model="value2"
                                     placeholder="请选择"
                                     open-direction="bottom"
                                     :show-labels="false"
                                     trackBy="id"
                                     label="name"
                                     @select="chooseSelect2"
                                     :options="selectoptions2">
                        </multiselect>
                      </div>
                      <div class="listwrapper">
                        <div @click="chooselist(2,index,item)" class="listitem" :class="selectItemIndex2 == index?'coloractive':''" v-for="(item,index) in selectList2" :key="item.id">{{item.name}}<span style="float: right" v-if="selectItemIndex2 == index"> 》</span></div>
                      </div>
                    </div>
                    <div class="detail" :style="{height:ispdf2?'':'100%'}">
                      <div v-if="!ispdf2" class="markdown-body editor" v-html="articleDetail2.post_content"></div>
                      <div class="img-wrapper" v-if="ispdf2" @click="pdfshowClick(2,articleDetail2.more.files)">
                        <img class="img1" src="../assets/pic_mrfm_wj@2x.png"/>
                      </div>
                    </div>
                  </div>
                  <div class="pdf-wrapper"  v-show="showpdf2">
                    <div class="body-content" style="height:850px;">
                      <v-touch @swipeleft="changeindexleft(2)" @swiperight="changeindexright(2)">
                      <div id="magazine2" style="height:850px;width:1200px;margin-left:0 !important;">

<!--                        <div v-for="(item, index) in pdfPicturePath2" :key="`test_${index}`">-->
<!--                          <div>-->
<!--                            <v-touch @swipeleft="changeindexleft(2)" @swiperight="changeindexright(2)">-->
<!--                              <img :src="item.pic" class="pdf_pic" />-->
<!--                            </v-touch>-->
<!--                          </div>-->
<!--                        </div>-->
                      </div>
                      </v-touch>
                      <div style="margin: 0 auto; text-align: center; display: none">
                        <div id="docView2" ref="docView2"></div>
                      </div>
                    </div>

                  </div>
                </div>
              </div>

            </div>
          </div>

          <div class="item_3">
            <div class="picwrapper" v-show="showfengmian3">
              <div class="initem" v-if="categoryslist[4]" @click="fengmianclick(3,4)">
                <img :src="categoryslist[4].more.thumbnail"/>
                <div class="intitle">{{categoryslist[4].name}}</div>
              </div>
              <div class="initem"  v-if="categoryslist[5]" @click="fengmianclick(3,5)">
                <img :src="categoryslist[5].more.thumbnail"/>
                <div class="intitle">{{categoryslist[5].name}}</div>
              </div>
            </div>

            <div class="detailwrapper" v-show="!showfengmian3">
              <div class="dtop">
                <img src="../assets/pic_qyzc_shrcxzsy.png"/>
              </div>
              <div class="btmwrapper">
                <div class="left">
                  <img src="../assets/icon_fanhui.png" @click="backtoshow(3)"/>
                </div>
                <div class="right">
                  <div class="content" v-show="!showpdf3">
                    <div class="listdetailwrapper">
                      <div class="listtop">
                        <multiselect v-model="value3"
                                     placeholder="请选择"
                                     open-direction="bottom"
                                     :show-labels="false"
                                     trackBy="id"
                                     label="name"
                                     @select="chooseSelect3"
                                     :options="selectoptions3">
                        </multiselect>
                      </div>
                      <div class="listwrapper">
                        <div @click="chooselist(3,index,item)" class="listitem" :class="selectItemIndex3 == index?'coloractive':''" v-for="(item,index) in selectList3" :key="item.id">{{item.name}}<span style="float: right" v-if="selectItemIndex3 == index"> 》</span></div>
                      </div>
                    </div>
                    <div class="detail" :style="{height:ispdf3?'':'100%'}">
                      <div v-if="!ispdf3" class="markdown-body editor" v-html="articleDetail3.post_content"></div>
                      <div class="img-wrapper" v-if="ispdf3" @click="pdfshowClick(3,articleDetail3.more.files)">
                        <img class="img1" src="../assets/pic_mrfm_wj@2x.png"/>
                      </div>
                    </div>
                  </div>
                  <div class="pdf-wrapper"  v-show="showpdf3">
                    <div class="body-content" style="height:850px;">
                      <v-touch @swipeleft="changeindexleft(3)" @swiperight="changeindexright(3)">
                      <div id="magazine3" style="height:850px;width:1200px;margin-left:0 !important;">
<!--                        <div v-for="(item, index) in pdfPicturePath3" :key="`test_${index}`">-->
<!--                          <div>-->
<!--                            <v-touch @swipeleft="changeindexleft(3)" @swiperight="changeindexright(3)">-->
<!--                              <img :src="item.pic" class="pdf_pic" />-->
<!--                            </v-touch>-->
<!--                          </div>-->
<!--                        </div>-->
                      </div>
                      </v-touch>
                      <div style="margin: 0 auto; text-align: center; display: none">
                        <div id="docView3" ref="docView3"></div>
                      </div>
                    </div>

                  </div>
                </div>
              </div>

            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import drawMixin from "../utils/drawMixin";
import "github-markdown-css/github-markdown.css"
import fullscreen from "@/views/fullscreen";
import Multiselect from "vue-multiselect";
import $ from "jquery";
import * as PDFJS from "pdfjs-dist";
import turn from "../utils/lib/turn.min.js"
import M from "../model/m";

export default {
  mixins: [ drawMixin ],
  data() {
    return {

      categoryslist:[],   //首页的分类列表, 一共有六个分类

      //下拉选择框 三个
      selectoptions1:[
      ],
      selectoptions2:[],
      selectoptions3:[],
      //下拉选择框的值 三个
      value1:{},
      value2:{},
      value3:{},
      //下拉选择后的列表 三个
      selectList1:[],
      //列表中选中的标记, 主要是为了显示 条目中的小箭头
      selectItemIndex1:-1,
      selectList2:[],
      selectItemIndex2:-2,
      selectList3:[],
      selectItemIndex3:-3,

      //标记pdf记号
      ispdf1:false,
      ispdf2:false,
      ispdf3:false,


      //showpdf div的标记
      showpdf1:false,
      showpdf2:false,
      showpdf3:false,


      showfengmian1:true,
      showfengmian2:true,
      showfengmian3:true,

      articleDetail1:{},
      articleDetail2:{},
      articleDetail3:{},



      pdfPicturePath1: [], // pdf转化的图片地址
      pdfPicturePath2: [], // pdf转化的图片地址
      pdfPicturePath3: [], // pdf转化的图片地址

      loading:true,
    }
  },
  components: {
    fullscreen,
    Multiselect
  },


  computed:{

  },


  mounted() {

    this.initData();


    //this.timeFn()

    //this.readPdf("bbb.pdf")
    this.cancelLoading();
    this.$refs.fullscreen.toggleFullScreen();



  },


  beforeDestroy () {

  },
  methods: {

    chooseSelect1(selectoption){
      this.getSelectList(selectoption,1);
    },

    chooseSelect2(selectoption){
      this.getSelectList(selectoption,2);
    },

    chooseSelect3(selectoption){
      this.getSelectList(selectoption,3);
    },

    initData(){
      //得到首页的图片列表
      M.getCategorys().then(res=>{
        this.categoryslist = res.data.categories;
      })
    },



    //封面被点击
    fengmianclick(index,categoryslistindex){
      console.log(index,categoryslistindex);
      //index 表示是哪一列中的(本屏一共有三列)
      //categoryslistindex  被点击的在 categoryslist中的index
      let showfengmianX = "showfengmian"+index;
      this[showfengmianX] = false;
      let thecategory = this.categoryslist[categoryslistindex];
      M.getCategorys(thecategory.id).then(res=>{
        let selectoptions = res.data.categories;
        let selectoptionsX = "selectoptions"+index;
        this[selectoptionsX] = selectoptions;
        let valueX = "value"+index;
        this[valueX] = selectoptions[0];
        //这里要显示默认的项的信息
        this.getSelectList(selectoptions[0],index);
      })
    },


    getSelectList(value,index){
      //index表示第几列的
      let params = {
        category_id:value.id
      }
      M.getselectLists(params).then(res=>{
        console.log(res);
        let selectListX = "selectList"+index;
        let selectlist = res.data.map(i=>{
          i.name=i.post_title;
          if(i.tag == 0){
            i.type = "txt"
          }else if(i.tag == 1){
            i.type = "pdf";
          }
          return i;
        });
        this[selectListX] = selectlist;
        let selectItemIndexX = "selectItemIndex"+index;
        this[selectItemIndexX] = 0;
        let theselectItem = selectlist[0];
        this.getArticleDetail(theselectItem,index);
      })
    },


    //通过文章id来显示文章的详情
    getArticleDetail(theselectItem,index){
      //index 第几列
      if(!theselectItem){
        let articleDetailX = "articleDetail"+index;
        this[articleDetailX] = [];
        return;
      }
      let ispdfX = "ispdf"+index;
      let article_id = theselectItem.id;
      this[ispdfX] = theselectItem.type == "pdf"?true:false
      M.getArticleDetail(article_id).then(res=>{
        let articleDetailX = "articleDetail"+index;
        this[articleDetailX] = res.data;
        if(theselectItem.type == "pdf"){
          this.readPdf(res.data.more.files[0].url,index);
          //this.readPdf("bbb.pdf?"+Math.random(),index)
        }
      })
    },


    //回退
    backtoshow(index){
      //index 表示是哪一列中的(本屏一共有三列)
      let showpdfX = "showpdf"+index;
      //当 showpdfX == true是 一定是显示了pdf 的滑动页
      if(this[showpdfX]){
        this[showpdfX] = !this[showpdfX]
      }else{
        //如果是showpdfX 是 false ,那就应该是退回上一级的页面
        let showfengmianX = "showfengmian"+index;
        this[showfengmianX] = true;
      }
    },


    pdfshowClick(index,files){
      //index 表示是哪一列中的(本屏一共有三列)
      let showpdfX = "showpdf"+index;
      this[showpdfX] = true;
      //是在这里加载pdf ,还是在列表中点击的时候加载pdf 可以测试一下哪个要好一点
      //this.readPdf("bbb.pdf",index)
    },



    chooselist(index,listindex,item){
      //第一个index 表示是哪一列中的(本屏一共有三列)
      //listindex 表示点击的是哪一条数据
      let selectItemIndexX = "selectItemIndex"+index;
      this[selectItemIndexX] = listindex;
      let selectListX = "selectList"+index;
      //从selectListX中的数组中得到这条信息的具体内容,并标记是否是一个pdf文件
      //看后台的设计,这里可能是要请求接口的
      let ispdfX = "ispdf"+index;
      this[ispdfX] = this[selectListX][listindex].type == "pdf"?true:false
      this.getArticleDetail(item,index)
    },



    //书翻页
    changeindexleft(index){
      this.$nextTick(()=>{
        if(index == 1){
          $("#magazine1").turn("next")
        }else if(index == 2){
          $("#magazine2").turn("next")
        }else if(index == 3){
          $("#magazine3").turn("next")
        }
      })


    },
    changeindexright(index){
      this.$nextTick(()=>{
        if(index == 1){
          $("#magazine1").turn("previous")
        }else if(index == 2){
          $("#magazine2").turn("previous")
        }else if(index == 3){
          $("#magazine3").turn("previous")
        }
      })

    },

//初始化pdf插件
    /*
     ** @param fileUrl pdf有效的查看地址
     **				(1、线上地址(如:http://www.xxx.com)
     **				2、本地public地址(例如:/static/view.pdf))
     ** @param  pdfPicturePath1 pdf转化的图片地址-用于放大查看所有pdf图片
     */
    readPdf(fileUrl,index) {
      let self = this;
      if(index == 1){
        let loadingTask1 = PDFJS.getDocument(fileUrl);  //读取pdf文件
        console.log(loadingTask1, '-----------loadingTask');
        loadingTask1.promise
            .then(function (pdf) {
              if (pdf) {
                // pdf 总页数
                const pageNum = pdf.numPages;
                for (let i = 1; i <= pageNum; i++) {
                  // 生成每页 pdf 的 canvas
                  const canvas = document.createElement('canvas');
                  canvas.id = 'page'+index+'Num' + i;
                  canvas.className = 'h'+index;
                  // 将 canvas 添加到 dom 中,docView(存放canvas的div)
                  let docViewX = "docView"+index;
                  console.log(docViewX);
                  self.$refs[docViewX].append(canvas);
                  //getContext() 方法返回一个用于在画布上绘图的环境。
                  const context = canvas.getContext('2d');
                  self.openPage(pdf, i, context);
                }
                setTimeout(() => {
                  self.exportImg(self,index);
                }, 2000);
              }
            })
            .catch(function (reason) {
              console.error('Error: ' + reason);
            });
      }
      if(index == 2){
        let loadingTask2 = PDFJS.getDocument(fileUrl);  //读取pdf文件
        console.log(loadingTask2, '-----------loadingTask');
        loadingTask2.promise
            .then(function (pdf) {
              if (pdf) {
                // pdf 总页数
                const pageNum = pdf.numPages;
                for (let i = 1; i <= pageNum; i++) {
                  // 生成每页 pdf 的 canvas
                  const canvas = document.createElement('canvas');
                  canvas.id = 'page'+index+'Num' + i;
                  canvas.className = 'h'+index;
                  // 将 canvas 添加到 dom 中,docView(存放canvas的div)
                  let docViewX = "docView"+index;
                  console.log(docViewX);
                  self.$refs[docViewX].append(canvas);
                  //getContext() 方法返回一个用于在画布上绘图的环境。
                  const context = canvas.getContext('2d');
                  self.openPage(pdf, i, context);
                }
                setTimeout(() => {
                  self.exportImg(self,index);
                }, 2000);
              }
            })
            .catch(function (reason) {
              console.error('Error: ' + reason);
            });
      }
      if(index == 3){
        let loadingTask3 = PDFJS.getDocument(fileUrl);  //读取pdf文件
        console.log(loadingTask3, '-----------loadingTask');
        loadingTask3.promise
            .then(function (pdf) {
              if (pdf) {
                // pdf 总页数
                const pageNum = pdf.numPages;
                for (let i = 1; i <= pageNum; i++) {
                  // 生成每页 pdf 的 canvas
                  const canvas = document.createElement('canvas');
                  canvas.id = 'page'+index+'Num' + i;
                  canvas.className = 'h'+index;
                  // 将 canvas 添加到 dom 中,docView(存放canvas的div)
                  let docViewX = "docView"+index;
                  console.log(docViewX);
                  self.$refs[docViewX].append(canvas);
                  //getContext() 方法返回一个用于在画布上绘图的环境。
                  const context = canvas.getContext('2d');
                  self.openPage(pdf, i, context);
                }
                setTimeout(() => {
                  self.exportImg(self,index);
                }, 2000);
              }
            })
            .catch(function (reason) {
              console.error('Error: ' + reason);
            });
      }


    },
    //pdf转成canvas
    /*
     ** @param loading pdf生成图片时的加载状态
     ** @param scale 控制 canvas显示的大小
     ** @param  pdfPicturePath1 pdf转化的图片地址-用于放大查看所有pdf图片
     */
    openPage(pdfFile, pageNumber, context) {
      let that = this;
      pdfFile.getPage(pageNumber).then(function (page) {
        // reference canvas via context
        let viewport = page.getViewport({scale:1});
        let scale =(847 / viewport.height).toFixed(2)
        let viewport1 = page.getViewport({scale:scale});

        let canvas = context.canvas;
        canvas.width = viewport1.width;
        canvas.height = viewport1.height;
        canvas.style.width = '100%';
        canvas.style.height = '100%';

        let renderContext = {
          canvasContext: context,
          viewport: viewport1
        };
        page.render(renderContext);
        that.loading = false;
      });
      return;
    },
    //canvas转成图片(可根据具体情况,进行图片转化显示)这里我把所有图片的base64存放在数组里面,方便放大查看,也可以直接把生成图片标签进行图片展示
    // 转图片
    exportImg(self,index) {

      //let canvaslist= document.querySelectorAll('canvas');
      let canvaslist = document.getElementsByClassName("h"+index);
      let pdfPicturePathX = "pdfPicturePath"+index;
      this[pdfPicturePathX] = [];
      //这里把所有的图片地址放入到 pdfPicturePath1 数组中去
      for (let i = 0; i < canvaslist.length; i++) {
        // let canvas = document.getElementById("pageNum" + (i + 1));
        // // 将 canvas 转成 base64 格式的图片
        // let base64ImgSrc = (canvas as any).toDataURL("image/png")
        // const img = document.createElement("img")
        // img.setAttribute('class', 'pdf-img');
        // img.src = base64ImgSrc
        // img.style.width = '100%';
        // // 将图片挂载到 dom 中
        // (self.$refs as any).docView.append(img);
        let canvasNode = document.getElementById('page'+index+'Num' + (i + 1));
        // 将 canvas 转成 base64 格式的图片
        if(canvasNode){
          this[pdfPicturePathX].push({page: i + 1, pic: canvasNode.toDataURL('image/png'), name: i + 1})
        }else {
          continue;
        }
        //console.log('--------------aaa-------------', this.pdfPicturePath1);
      }

      this.$nextTick(()=>{
        if(index == 1){
          if($("#magazine1").children().length > 0){
            $("#magazine1").turn("destroy");
            $("#magazine1").children().remove();
          }
          let magazine1 = $("#magazine1");
          this[pdfPicturePathX].forEach(i=>{
            magazine1.append("<img src='"+i.pic+"'/>")
          });

          //setTimeout(()=>{

            $("#magazine1").turn({
              autoCenter: true,
              elevation: 50,
              acceleration: true,
              //direction:"rtl",
              // when: {
              //   turned: function() {
              //     //当前页
              //     // console.log("Current view: ", $(this).turn("view"));
              //     // //总页数
              //     // console.log(
              //     //     "#magazine has " + $("#magazine").turn("pages") + " pages"
              //     // );
              //     //$("#magazine").turn("hasPage", 10);
              //     //$("#magazine").turn("pages", 1);
              //   }
              // }
            })
          $("#magazine1").turn("center");
          $("#magazine1").turn("page");

          //console.log($("#magazine1").turn("pages"));
            $("#magazine1").bind("start",function(e,p,c){
              if(c == "tl"||c == 'tr'){
                e.preventDefault();
              }
            })
          //},1000)



        }
        if(index == 2){
          if($("#magazine2").children().length > 0){
            $("#magazine2").turn("destroy");
            $("#magazine2").children().remove();
          }
          let magazine2 = $("#magazine2");
          this[pdfPicturePathX].forEach(i=>{
            magazine2.append("<div><img src='"+i.pic+"'/></div>")
          });
          $("#magazine2").turn("center");
          $("#magazine2").turn("page");
          $("#magazine2").turn({
            autoCenter: true,
            acceleration: true,
            //direction:"rtl",
            when: {
              turned: function() {
                //当前页
                // console.log("Current view: ", $(this).turn("view"));
                // //总页数
                // console.log(
                //     "#magazine has " + $("#magazine").turn("pages") + " pages"
                // );
                //$("#magazine").turn("hasPage", 10);
                //$("#magazine").turn("pages", 1);
              }
            }
          })
          $("#magazine2").bind("start",function(e,p,c){
            if(c == "tl"||c == 'tr'){
              e.preventDefault();
            }
          })
        }

        if(index == 3){
          if($("#magazine3").children().length > 0){
            $("#magazine3").turn("destroy");
            $("#magazine3").children().remove();
          }
          let magazine3 = $("#magazine3");
          this[pdfPicturePathX].forEach(i=>{
            magazine3.append("<div><img src='"+i.pic+"'/></div>")
          });
          $("#magazine3").turn("center");
          $("#magazine3").turn("page");
          $("#magazine3").turn({
            autoCenter: true,
            acceleration: true,
            //direction:"ltr",
            when: {
              turned: function() {
                //当前页
                // console.log("Current view: ", $(this).turn("view"));
                // //总页数
                // console.log(
                //     "#magazine has " + $("#magazine").turn("pages") + " pages"
                // );
                //$("#magazine").turn("hasPage", 10);
                //$("#magazine").turn("pages", 1);
              }
            }
          })
          $("#magazine3").bind("start",function(e,p,c){
            if(c == "tl"||c == 'tr'){
              e.preventDefault();
            }
          })
        }
      })
    },

    cancelLoading() {
      setTimeout(() => {
        this.loading = false
      }, 500)
    }
  }
}
</script>

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

<style lang="scss" scoped>
@import '../assets/scss/index.scss';

.row1{
  margin-top:109px;
  .title-wrapper{
    position:relative;
    padding-left:177px;
    &::before{
      position:absolute;
      left:100px;
      top:0;
      content:"";
      width:20px;
      height:226px;
      background:#00FBFF;
    }
  }
}
.row2{
  width:100%;
  height:1584px;
  display:flex;
  flex-flow: row nowrap;
  justify-content: space-between;
  align-items: center;
  padding:0 10px;
  .item_3{
    flex:1;
    width:100%;
    height:100%;
    display:flex;
    justify-content: center;
    align-items: center;
    .picwrapper{
      width:100%;
      height:1183px;
      display:flex;
      justify-content: space-between;
      align-items: center;
      padding:0 50px;
      .initem{
        width:978px;
        height:1183px;
        box-shadow: 0 0 10px 10px rgba(255,255,255,.4);
        border-radius: 20px;
        overflow: hidden;
        position: relative;
        img{
          width:987px;
          height:1183px;
          border-radius: 20px;
        }
        .intitle{
          position: absolute;
          font-size:130px;
          font-weight: bold;
          bottom:143px;
          text-align: center;
          width:100%;
          color:#fff;
          text-shadow:0px 0px 30px #023b92;
          letter-spacing: 10px;
        }
      }
    }
    .detailwrapper{
      width:100%;
      height:1370px;
      padding:0 50px;
      .dtop{
        overflow: hidden;
        img{
          transform: translate(-2%,0);
        }
      }
      .btmwrapper{
        display:flex;
        width:100%;
        height:947px;
        margin-top:20px;
        .left{
          flex-basis: 144px;
          img{
            position: relative;
            top:50%;
            transform: translate(0,-50%);
            width:100px;
            height:100px;
          }
        }
        .right{
          flex:1;
          box-shadow: rgba(255,255,255,.9) 0 0 20px inset;
          padding:50px;
          box-sizing: border-box;
          display:flex;
          justify-content: space-between;
          .content{
            width:100%;
            display:flex;
            justify-content: space-between;
            align-items: center;
            .listdetailwrapper{
              width:885px;
              height:auto;
              .listtop{
                width:769px;
                ::v-deep .multiselect--active{
                  .multiselect__select{
                    z-index: 100;
                  }
                  .multiselect__input{
                    color:#fff !important;
                  }
                }
                ::v-deep .multiselect{
                  min-height:100px;
                  font-size: 56px !important;
                  .multiselect__select{
                    width: 100px;
                    height: 100px;
                    line-height: 76px;
                    background: #FFDC24;
                    border-radius: 50px;
                    margin-top: 10px;
                    &:before{
                      border-width: 25px 18px 0;
                    }
                  }
                  .multiselect__tags{
                    min-height: 100px;
                    font-size: 56px;
                    line-height: 100px;
                    background:#2B6CD2;
                    .multiselect__input{
                      min-height:100px;
                      line-height: 100px;
                      font-size:56px;
                      background:#2B6CD2;
                      color:#fff !important;
                    }
                    .multiselect__single{
                      min-height:100px;
                      line-height: 100px;
                      font-size:56px;
                      background:none;
                      color:#fff;
                    }
                  }
                  .multiselect__content-wrapper{
                    max-height: 700px !important;
                    .multiselect__option{
                      min-height: 100px;
                      line-height: 100px;
                    }
                  }
                }
                ::v-deep .multiselect__option--highlight{
                  background:#aaa;
                }
              }
              .listwrapper{
                width:100%;
                height:720px;
                overflow-y:scroll;
                -webkit-overflow-scrolling : touch;
                &::-webkit-scrollbar { width: 0 !important }
                .coloractive{
                  color:#FFDC24 !important;
                }
                .listitem{
                  height:110px;
                  font-size:56px;
                  line-height: 110px;
                  color:#fff;
                  padding:0 20px;
                  box-sizing: border-box;
                  text-overflow: ellipsis;
                  overflow: hidden;
                  white-space: nowrap;
                  width:95%;
                  span{
                    font-size:30px;
                    display: inline-block;
                    height:110px;
                    float:right;
                    line-height: 110px;
                    color:#FFDC24;
                    margin-right:40px
                  }
                  &:hover{
                    background:rgba(255,255,255,0.3);
                    color:#FFDC24
                  }
                }
              }
            }
            .detail{
              flex:1;
              padding:20px;
              box-sizing: border-box;
              overflow-y: scroll;
              &::-webkit-scrollbar{
                width:0;
              }
              .editor{
                background:none;
                font-size:50px;
                color:#fff;
              }
              .img-wrapper{
                width:500px;
                hieght:587px;
                margin:0 auto;
                background:url("../assets/pic_rczc_ym1.png") no-repeat center right;
                .img1{
                  width:441px;
                  height:587px;
                }
              }
            }
          }

          .pdf-wrapper{
            width:100%;
            display:flex;
            justify-content: center;
            align-items: center;
            .decit{
              font-size:56px;
              z-index: 1000;
            }
          }
        }
      }
    }
  }
}
</style>

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

说一下这个项目, 这个项目中使用 turnjs 的时候
只能 倒翻书, 不能正翻书, direction:“rtl”, 只能rtl才生效, 如果是 ltr 就是出错,无效果
后来找到了另外一个解决办法 v-touch 就是解决的办法
首先 禁止掉 turnjs 的翻页效果

			//这段代码就是禁止 turnjs 的翻书效果
            $("#magazine1").bind("start",function(e,p,c){
              if(c == "tl"||c == 'tr'){
                e.preventDefault();
              }
            })

然后, 使用 v-touch 监听 左右滑动

    //书翻页
    changeindexleft(index){
      this.$nextTick(()=>{
        if(index == 1){
          $("#magazine1").turn("next")
        }
      })
    },
    changeindexright(index){
      this.$nextTick(()=>{
        if(index == 1){
          $("#magazine1").turn("previous")
        }
      })
    },

这样书就可以 前后翻动了 解决了 turnjs 只能 倒翻书的问题
还有一个问题, 就是 因为,本页面会加载不同的pdf 文件, 而 turnjs 初始化后 $(“#magazine1”).turn();会在 其中添加很多其它的标记, 如果在 $(“#margazine1”).turn()初始化完成之后 , 再执行一次 $(“#margazine1”).turn();就会形成无限的嵌套,导至显示出错。
最初我使用的是 vue 的数据改变来 更改 pdf 图片的显示, 就踩了上面的坑, 后来经过分析, 我在代码中使用了 jquery 的方法来改变数据
上面的代码中

vue中使用pdfjs-dist + turnjs实现页面的翻书浏览功能

以上便是我使用 vue pdf-dist 和turnjs做翻页的心得

原文地址:https://blog.csdn.net/hjh15827475896/article/details/127609539