我们公司之前的需要实现的功能 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)