PDF.js查找功能实现浅析

PDF.js查找功能实现浅析

说明

最近要做一个类似于PDF阅读器的项目,基于文本查找全部高亮实现一些别的功能;看着PDF.js功能还比较齐全,就准备把这个改改拿来用了。

只是我对前端一窍不通(目前也懒得去学),所以我的目的是找到PDF.js这个项目里面我需要的代码,直接拿来cv就能用、或者只需要改那么几行就能用;在这里记录一下我阅读的过程,相应方法是如何实现的我并不会记录(看不懂),也恳请各位对我的记录进行补充或者指正。

cv

在这里提到的代码所在行数可能会因为PDF.js版本的更新而改变;

正题

PDF.js官网下载地址:https://mozilla.github.io/pdf.js/getting_started/#download

来看看它的项目结构:
项目结构

从文件夹的名字我们就可以看出,build中的文件我们是不用管的(至少我是不会去看的);需要cv的主要时web文件夹下的东西。

根据官网的说明,直接点开web/viewer.js我们就可以直接看到PDF.js的界面了:
PDF.js界面
打开控制台,直接定位到搜索框的位置那去(85行往下都是搜索工具栏的组件描述):
在这里插入图片描述
(好家伙,一个onclick都没有)(优雅的代码就是不一样)

那么viewer.html我们就没什么好看的了;接下来我们打开viewer.js,定位到131行,可以看到这里将viewer.html的所有元素通过id获取了出来。定位到201行,findbar就是所有和查找功能有关的元素。
findbar

接下来的目标就是寻找它们的事件:选取findField变量(findField是查找的输入框),直接右键点击Find Usages,可以看到第5660行的引用,将这个元素的输入事件绑定了监听器。
在这里插入图片描述
findBar中的其余元素同样在PDFFindBar.constructor()中绑定了监听器。

接下来查看监听器监听到了事件之后会触发的dispatchEvent()函数;跳转到5700行:
dispatchEvent
eventBus是什么我不清楚;this.eventBus.dispatch()这个方法在哪定义的我也没找到;这个方法的第二个参数用花括号围起来的一大堆是个什么语法我也没见过;不过dispatch这个单词我认得就可以让我们读懂这个方法了:
这个方法的作用还是发布事件,事件类型是"find",事件的状态就是花括号里面的那一堆。(我代码阅读量不高,不知道嵌套发布事件的写法常不常见)

然后就是寻找"find"类型事件的监听器:
在文本中搜索"find"(带上双引号,不然会出来两百多个结果),可以找到六处:三处发布事件,一处case语句判断事件类型,还有两处分别位于1730行与1864行。

先来看1730行:
绑定find
选中_on()方法,寻找定义,转到3592行:
_on
可以看出来_on()方法是将事件类型eventName与监听器listener绑定;所以1730行的意思是事件"find"发生时,将该事件传入webViewerFind()方法中,作为其参数;

同理,第1864行的意思很容易想到:取消绑定。
在这里插入图片描述

接下来转到2437行查看webViewerFind()方法:
webViewerFind()
可以看到这个方法的主要功能是调用executeCommand()这个方法;第一个参数为cmd,将evt.type前面加了个"find";而evt.type就是前面提到的dispatchEvent()中的type参数。剩下的参数就是照搬evt的了。

分界线

接下来我阅读代码的思路就比较混乱了。一些结论的原因我可能不会给出,因为我自己都忘了那些结论是怎么来的了。

跳转到5936行查看executeCommand()方法:
executeCommand
在这个方法中调用了三个方法值得关注:
首先是_extractText()方法,这个方法的功能为将pdf文件的所有文本提取出来,按页保存在PDFFindController._pageContents[]中;这个方法提取出来的文本会用于之后的查找。

其次是_updateAllPages()方法;这个方法稍后再提;

最后是_nextMatch()方法,位于6296行。
这个方法的具体作用我语言组织不起来…没完全读懂,不过没看懂这个方法并不影响我cv,所以我把我的注释放在这里,以供参考:

_nextMatch() {
    const previous = this._state.findPrevious;      // findPrevious是点击寻找区的按钮发布的事件的参数,只有点击左右箭头时才有这个参数,分别是true和false
    const currentPageIndex = this._linkService.page - 1;  // 当前查找所在页码-1
    const numPages = this._linkService.pagesCount;  // pdf页数
    this._highlightMatches = true;

    if (this._dirtyMatch) {   // this._dirtyMatch应该是不区分大小写查找    这下面设置的都是this._reset()方法中定义的变量
      this._dirtyMatch = false;
      this._selected.pageIdx = this._selected.matchIdx = -1;  // this._selected并无实际含义
      this._offset.pageIdx = currentPageIndex;  // this._offset并无实际含义
      this._offset.matchIdx = null;
      this._offset.wrapped = false;
      this._resumePageIdx = null;
      this._pageMatches.length = 0;
      this._pageMatchesLength.length = 0;
      this._matchesCountTotal = 0;

      this._updateAllPages(); // 发布名为updatetextlayermatches的事件,与_onUpdateTextLayerMatches绑定,其调用 _updateMatches()函数,位于11521行

      for (let i = 0; i < numPages; i++) {  // _pendingFindMatches这个变量只在这个循环内被调用,别处没有调用
        if (this._pendingFindMatches[i] === true) {
          continue;
        }

        this._pendingFindMatches[i] = true;

        this._extractTextPromises[i].then(pageIdx => {  // 相当于将padeIdx传入箭头右边花括号内的函数中 _extractTextPromises内的元素都是Promise类实例
          delete this._pendingFindMatches[pageIdx];     // 这里传入的参数pageIdx为_extractTextPromises[i]异步操作的结果

          this._calculateMatch(pageIdx);
        });
      }
    }

_nextMatch()方法最后调用了_calculateMatch()方法,转到6201行查看:

_calculateMatch()
其中phraseSearch和_calculateWordMatch()的作用我没有看懂;我将_calculateWordMatch()方法删除后并不影响程序运行。
phraseSearch应该是某个功能,不过并没有完全实现,所以没有调用_calculateWordMatch()方法。

_calculatePhraseMatch()位于6145行,功能为保存待查找字符在每一页字符(一维数组)中的位置;
_calculatePhraseMatch()

其调用的_isEntireWord()方法为判断在pdf文件中所匹配到的字符串是否为一个词,对应“字词匹配”功能,其位于6121行。

回到_calculateMatch()方法:
如果选中了“高亮全部”(highlightAll),则会调用_updatePage()方法更新界面,该方法位于6278行;

该函数发布的事件类型与_updateAllPages()相同,仅参数不同:该函数发布的事件的页码参数为当前页面参数,而_updateAllPages()为-1;
update

_updateAllPages()方法发布名为updatetextlayermatches的事件,与_onUpdateTextLayerMatches绑定,其调用 _updateMatches()方法,位于11522行;

_updateMatches()方法里面是干什么的看不懂,不过最后一行调用的this._renderMatches()应该就是函数为高亮全部的具体实现方法(毕竟人家翻译过来叫 渲染匹配)。
在这里插入图片描述

来到11425行, _renderMatches()方法,其余内容我没有去管,直接看到11457行以及11503行往后的内容,这几行就是实现查找全体高亮的核心内容。
span在这里插入图片描述

最后看一眼viewer.css:
在这里插入图片描述

现在心里大概知道该怎么cv这个代码了。折腾CSS去了。改成功了以后再放上来。

—————————第二分界线—————————

改不出来了不改了(告辞.jpg)

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值