PDF.js实现行定位功能(通过外部点击跳转到某一行)

我们公司之前的需要实现的功能  pdf上传、定位、浏览功能,这块主要我负责,就像上一个博客写的一样,遇到很多很多的问题,主要用到的js就是pdf.js,实现对上传pdf的浏览,上一个博客记录的是跨域问题(跨域问题是很重要的一个,因为一般文件服务器和项目服务器是分开的),下面记录一下如果实现的行定位功能。

       本来我是不打算用行定位的,因为之前考虑了一下是完全没有头绪的,因为pdf.js主要就是点击缩略图定位到对应的页码实现页码跳转的。因为用户点击不可能点击的是pdf.js内部的按钮,需要在外部添加按钮(相当于锚点功能)。主要功能点:锚点设置 和 锚点定位。

       下面我就只讲行定位的方法:

        思路:pdf.js有个目录功能,点击目录中的标题就实现了行定位,我就是受这个启发才去思考的实现行定位。首页通过页面F12去查看目录定位的连接,发现是一串编码(不知道啥格式),我就复制出来去网页中转码过来,发现格式如下:

#[{"num":23,"gen":0},{"name":"XYZ"},74,769,0]
#[{"num":46,"gen":0},{"name":"XYZ"},74,442,0]

这是其中二个标题对应的编码转换后的代码,我当时发现就二个地方是不同的,一个就是 num的值,另一个就是后面倒数第二个的数字,接下来就要去找源码了,一个一个的console,终于在viewer.js的9285行找到了端倪(由于每个版本的行数不一样,下面是我复制的那个js方法,因为加密电脑不能截图,只能给代码了):

key: '_updateLocation',
value: function _updateLocation(firstPage) {
    var currentScale = this._currentScale;
    var currentScaleValue = this._currentScaleValue;
    var normalizedScaleValue = parseFloat(currentScaleValue)
    ...........

这个方法console方法当你滚动页面的时候就会走这个方法,这个方法中的后面有几个非常重要的参数

 this._location = {
     pageNumber: pageNumber,
     scale: normalizedScaleValue,
     top: intTop,
     left: intLeft,
     rotation: this._pagesRotation,
     pdfOpenParams: pdfOpenParams
};

通过打印能够发现其中的pageNumber就是当前页码,intTop 就是发现那个编码中的变化数字中的倒数第二个参数,解释为高度(哈哈,现在才知道不是记录的行,而是记录的当前页码的高度实现的“行定位”),现在第一个参数有了,主要目标就是那个num的值了,跟我们在页面看到的值完全不一样的,我就猜想一定是一个json或者数组啥的通过key value对应到的页码,然后我就通过这个方法顺藤摸瓜,找到了大本营:

{
    key: 'cachePageRef',
    value: function cachePageRef(pageNum, pageRef) {
     if (!pageRef) {
          return;
      }
    var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
     this._pagesRefCache[refStr] = pageNum;
     
 }
  }, {
    key: '_cachedPageNumber',
    value: function _cachedPageNumber(pageRef) {
    var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
    return this._pagesRefCache && this._pagesRefCache[refStr] || null;
}
  },

我这边大概在7139行(viewer.js),这二个方法狠狠重要,一个是页码(下面),一个是创建的key-value格式的编码(上面一个),通过console得知,当你加载pdf文件的时候就会去调用上面这个方法,将页码和编码对应(对应格式是“27 0 R”-“4”,4是value就是页码,前面是key就是编码)。

       到目前为止获取就有了(拨开云雾见青天)的感觉,下面就是获取了,上面说过9千多行那个滚动页面就会走的那个方法,那几个参数,其中的intTop就是我们需要的高度的值,页码需要通过那个key-value获取,所以我开始修改了源码。

       我们需要实时的获取当前页的数据

 this._location = {
     pageNumber: pageNumber,
     scale: normalizedScaleValue,
     top: intTop,
     left: intLeft,
     rotation: this._pagesRotation,
     pdfOpenParams: pdfOpenParams
};
//下方是我添加的代码(这里你需要在viewer.html页面中加入二个隐藏的input,id为page_top和page_cache)
    var page_top = document.getElementById("page_top");
    page_top.value = this._location.top;
    var page_cache = document.getElementById("page_cache");
    page_cache.value = this.getPageCache(this._location.pageNumber);

最后一行那个getPageCache方法是我修改的源码:

 this._location = {
     pageNumber: pageNumber,
     scale: normalizedScaleValue,
     top: intTop,
     left: intLeft,
     rotation: this._pagesRotation,
     pdfOpenParams: pdfOpenParams
};
//下方是我添加的代码(这里你需要在viewer.html页面中加入二个隐藏的input,id为page_top和page_cache)
    var page_top = document.getElementById("page_top");
    page_top.value = this._location.top;
    var page_cache = document.getElementById("page_cache");
    page_cache.value = this.getPageCache(this._location.pageNumber);
 }
  },{//下面是我添加的方法
//这个方法用来获取对应num的页码cache
    key:'getPageCache',
    value:function getPageCache(pageNum){
    //循环结果(这里的page_cache是一个数组,下面细说)
    var str = JSON.stringify(page_cache);
    //	console.log("格式为:"+typeof(JSON.parse(str)))
//	console.log("json的数据:"+str)
    for(var key in JSON.parse(str)){
        if(JSON.parse(str)[key]==pageNum){
                return key;
	}
				}
	}

我们上面有说那个key-value格式的数据,因为不是一个代码块中,所在我在js的最上方加上了一个全局变量page_cache

//定义全局变量   去接受页码对应编码值
var page_cache = [];

然后在页面加载pdf的时候也给这个数组赋值一下:

{
    key: 'cachePageRef',
    value: function cachePageRef(pageNum, pageRef) {
     if (!pageRef) {
          return;
      }
    var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
     this._pagesRefCache[refStr] = pageNum;

       //当赋值完毕之后,给全局赋值,这样我就获取到这个编码了
       page_cache =  this._pagesRefCache;

     
 }
  }, {
    key: '_cachedPageNumber',
    value: function _cachedPageNumber(pageRef) {
    var refStr = pageRef.num + ' ' + pageRef.gen + ' R';
    return this._pagesRefCache && this._pagesRefCache[refStr] || null;
}
  },

这样就如上面,通过这个全局去获取对应的编码值。(整个获取就到此结束了(设置锚点))

补充一下:有的人可能不会获取iframe下的文件,发一下我的这个:

//这个是子页面


//js
top = $("#iframe01").contents().find("#page_top").val();
cache = $("#iframe01").contents().find("#page_cache").val().split(" ")[0];
console.log("父页面获取的top:"+$("#iframe01").contents().find("#page_top").val());
console.log("父页面获取的页码编码:"+$("#iframe01").contents().find("#page_cache").val());

这样就获取了那个编码中的num和那个高度的值了。

 

下面就是实现定位了(锚点点击定位):直接上代码

//html




//jq

//这个才是定位
$(".set1").click(function(){
    $(".set2").click();
    //始终在页面只有一个是模拟添加的a标签
    if($("#iframe01").contents().find(".addLink").length!=0){
        $("#iframe01").contents().find(".addLink").remove();
    }
    //创建一个模拟目录中的标题a标签
    str = "

"; //添加到子页面中 //先判断是否有 没有再添加 有就不添加 if($("#iframe01").contents().find("#p37318").length==0){ $("#iframe01").contents().find("body").append(str); } //模拟目录a标签的点击事件 $("#iframe01").contents().find("#p37318").find("p")[0].click(); }) //这个是假的 $(".set2").click(function(){ if($("#iframe01").contents().find(".addLink").length!=0){ $("#iframe01").contents().find(".addLink").remove(); } str = "

GG

"; if($("#iframe01").contents().find("#p17192").length==0){ $("#iframe01").contents().find("body").append(str); } $("#iframe01").contents().find("#p17192"). find("p")[0].click(); })

思路:发现目录的a标签的事件和class,后台传的数据有那二个参数,创建一个类似的a标签,将参数放进去,然后放到子页面中,点击的时候去找到我们新增的a标签,触发点击,实现跳转,这里的set1是跳转的。因为在我的本地一个点击当你滚动的时候,再次点击就不行了,失效。所以又加了一个隐藏的点击,每次点击先触发一下隐藏的点击。发现可用。

 

有很多人都遇到这种问题了。也不用去找我了,通过需要的内容设置定位点以及跳转到定位点我在github写了一个小demo,有兴趣的可以下载试试https://github.com/Ma-Tao007/pdfdemo2

 

整个模拟行定位实现完毕。用了我一整天的时间,但是最后的结果还是让我极其欣慰的。由于发不了源码,如果大家看到这个又不懂的可以找我,评论就行,一天内一定回复。(2568819232加QQ也行,备注CSND即可,QQ因为问题忘了,有问题的可以加我vx吧:15056408321)

你可能感兴趣的:(java心得)