【番外篇】前端頁面如何優(yōu)雅的顯示PDF:實現(xiàn)文字搜索功能

th.jpeg
  • 導讀

之前花了一部分時間研究pdf.js 在react 上面的使用髓霞,也寫了五篇文章記錄自己的學習成果筐咧,實現(xiàn)了簡單的pdf預覽和工具欄的翻頁强戴、縮放责鳍,文字復制的簡單功能以及采用虛擬dom的方式優(yōu)化頁數(shù)比較多的情況下渲染慢的問題肩钠。但是有一個關(guān)鍵的功能沒有實現(xiàn)就是pdf文字查找功能泣港,這篇我們就實現(xiàn)一下這個功能

推薦閱讀

修改渲染方式

如果你看過前幾篇文章坡氯,就會知道我們之前的渲染方式是通過創(chuàng)建一個承載pdf的canvas標簽通過pdf.render()的方式渲染到創(chuàng)建的canvas晨横,如果需要渲染pdf的文字需要創(chuàng)建一個與canvas樣式一樣的div承載文字信息,就可以實現(xiàn)pdf里面文字的右鍵復制功能箫柳。

當然了渲染PDF的方式不止上面一種,上面那種也是官網(wǎng)不太推薦的使用方式手形,因為pdf.js 已經(jīng)實現(xiàn)了一個pdf預覽的viewer,我們可以直接拿來使用

import { PDFLinkService, PDFFindController, PDFViewer } from 'pdfjs-dist/web/pdf_viewer';

const linkService = new PDFLinkService();
const findController = new PDFFindController({
  linkService,
});
const newViewer = new PDFViewer({
  container: containerRef.current,
  linkService,
  useOnlyCssZoom: USE_ONLY_CSS_ZOOM,
  textLayerMode: TEXT_LAYER_MODE,
  // renderer:'svg',
  findController,
});
linkService.setViewer(newViewer);
// 設(shè)置初始縮放
newViewer.currentScaleValue = scale;

以上方法注冊了一個pdf預覽的viewer 對應(yīng)的html如下

<div
  id="viewerContainer"
  className="viewerContainer"
  ref={containerRef}
  >
  <div
  className="pdfViewer"
  id="innerContainer"
  />
  </div>
</div>

以上代碼我也是根據(jù)pdf.js 給出的例子不斷的摸索出來的悯恍,有些內(nèi)容也是一知半解库糠,這里只解釋我會的東西

new PDFViewer({}) 官方給提供的一個viewer,pdf.js中demo例子上面所有的功能都在這個viewer中涮毫,本節(jié)需要有查找功能用到 PDFFindController(),把它作為參數(shù)傳給viewer瞬欧。在后面使用他的 viewer.findController.executeCommand('findagain', searcher);方法進行查找,searcher 查找對象在后面會說明里面內(nèi)容

其他參數(shù)說明

  • container 顯示PDF的容器dom罢防,在他里面需要有一個div顯示PDF頁面信息艘虎,一個頁面是一個div,里面div的className建議使用pdfViewer可以直接使用pdf.js提供的樣式篙梢,(也可以自己寫樣式比較費勁)
  • linkService 不是很懂顷帖,但是需要^?_?^
  • useOnlyCssZoom 是否可以通過css控制頁面的縮放,默認 false
  • textLayerMode 是否顯示文字 默認0 不顯示,1 顯示
  • findController 傳入文字查找控制器

還有一些別的參數(shù)

  • render 渲染的類型 默認是canvas 可選svg
  • maxCanvasPixels 最大canvas像素
  • enablePrintAutoRotate 啟用打印旋轉(zhuǎn)

如果使用這個viewer 還有一些屬性通過newViewer對象直接訪問

  • pagesCount 總頁數(shù)
  • pageViewsReady 是否渲染完成渤滞,通過這個屬性判斷是不是所有的頁面都渲染完成,因為pdf渲染是異步的榴嗅,有一些事件監(jiān)聽是需要渲染完成后再進行
  • currnetPageNumber 當前頁碼妄呕,翻頁使用
  • currentScale 縮放比率,設(shè)置頁面縮放需要用currentScaleValue
  • pagesRotation 頁面旋轉(zhuǎn)
  • isPageVisible(pageNumber) 傳入頁碼判斷頁面是否不可見

以上就是使用PDFViewer()實現(xiàn)預覽的基本理論和相關(guān)使用到的參數(shù)

開始編碼

進入頁面創(chuàng)建viewer

const initialViewer = (url) => {
  const linkService = new PDFLinkService();
  const findController = new PDFFindController({
    linkService,
  });
  const newViewer = new PDFViewer({
    container: containerRef.current,
    linkService,
    useOnlyCssZoom: true,
    textLayerMode: 1,
    // renderer:'svg',
    findController,
  });
  linkService.setViewer(newViewer);
  // 設(shè)置初始縮放
  newViewer.currentScaleValue = scale;

  const loadingTask = pdfjs.getDocument({ url });
  loadingTask.promise.then(pdf => {
    if (pdf) {
      const nums = pdf.numPages
      setNumPages(nums)
      newViewer.setDocument(pdf);
      linkService.setDocument(pdf);
      setViewer(newViewer)
      // 判斷是否已經(jīng)渲染完畢
      const interval = setInterval(() => { loadPdf() }, 1000);
      function loadPdf() {
        if (newViewer.pageViewsReady) {
          // ... 渲染完成操作
        }
      }
    }
  })
}

對應(yīng)的html 就是上面的代碼嗽测,其中container是通過useRef 創(chuàng)建的

const containerRef = useRef(null)

實現(xiàn)翻頁和縮放

  • 翻頁

翻頁的實現(xiàn)就是改變上面提到的currentPageNumber值

viewer.currentPageNumber = num
  • 縮放

修改縮放的方式也是通過修改屬性值改變 currentScaleValue

viewer.currentScaleValue = newScale;

縮放的參數(shù)是有固定格式的绪励,如果是數(shù)字的話可以隨便多少就行,但是縮放也是可以是字符串形式的唠粥,如下:

<select
  value={`${scale}`}
  onChange={e => {
    const newScale = e.target.value
    viewer.currentScaleValue = newScale;
    setScale(newScale)
  }}
  >
  <option value="auto">自動縮放</option>
  <option value="page-actual">實際大小</option>
  <option value="page-fit">適合頁面</option>
  <option value="page-width">適合頁寬</option>
  <option value="0.50">50%</option>
  <option value="0.75">75%</option>
  <option value="1">100%</option>
  <option value="1.25">125%</option>
  <option value="1.50">150%</option>
  <option value="1.75">175%</option>
  <option value="2">200%</option>
  <option value="3">300%</option>
  <option value="4">400%</option>
</select>

文字查找

  • 定義查找對像
const [searcher = {}, setSearcher] = useState({
  phraseSearch: true, // 是否短語查找
  query: '', // 查詢字段
  findPrevious: true, // 是否循環(huán)查找
  highlightAll: true, // 是否高亮
});

用戶輸入的時候改變

<input
  type="text"
  id="searchInput"
  onChange={e => {
    setSearcher({
      ...searcher,
      query: e.target.value,
    });
  }}
/>

通過事件監(jiān)聽回車事件進行查找

# 使用 umi hooks 進行事件監(jiān)聽
useKeyPress('enter', event => {
        viewer.findController.executeCommand('findagain', searcher);
      });

回車查找進行了頁面的跳轉(zhuǎn)和循環(huán)查找

其他事件監(jiān)聽

  • 滾動頁碼 ,滾動時監(jiān)聽滾動到第幾頁
document.addEventListener('pagechanging', function (evt) {
  const page = evt.detail.pageNumber;
  changePage(page)
})

const changePage = (num) => {
  viewer.currentPageNumber = num
  setCurrentPageNumber(num)
}
  • 查詢統(tǒng)計
useEffect(() => {
  window.addEventListener('updatefindcontrolstate', e => {
    setMatchesCount(e.detail.matchesCount);
  });
  window.addEventListener('updatefindmatchescount', e => {
    setMatchesCount(e.detail.matchesCount);
  })
})
matchesCount: {
  current: // 當前查找的第幾項
  total: // 總共有幾項
}

源碼

https://github.com/LiuSandy/react-pdf-render

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疏魏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子晤愧,更是在濱河造成了極大的恐慌大莫,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件官份,死亡現(xiàn)場離奇詭異只厘,居然都是意外死亡烙丛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門羔味,熙熙樓的掌柜王于貴愁眉苦臉地迎上來河咽,“玉大人,你說我怎么就攤上這事赋元⊥罚” “怎么了?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵搁凸,是天一觀的道長寒瓦。 經(jīng)常有香客問我,道長坪仇,這世上最難降的妖魔是什么杂腰? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮椅文,結(jié)果婚禮上喂很,老公的妹妹穿的比我還像新娘。我一直安慰自己皆刺,他們只是感情好少辣,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著羡蛾,像睡著了一般漓帅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痴怨,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天忙干,我揣著相機與錄音,去河邊找鬼浪藻。 笑死捐迫,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的爱葵。 我是一名探鬼主播施戴,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萌丈!你這毒婦竟也來了赞哗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤辆雾,失蹤者是張志新(化名)和其女友劉穎肪笋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡涂乌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年艺栈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片湾盒。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡湿右,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出罚勾,到底是詐尸還是另有隱情毅人,我是刑警寧澤,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布尖殃,位于F島的核電站丈莺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏送丰。R本人自食惡果不足惜缔俄,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望器躏。 院中可真熱鬧俐载,春花似錦、人聲如沸登失。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽揽浙。三九已至状婶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馅巷,已是汗流浹背膛虫。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留令杈,地道東北人走敌。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像逗噩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子跌榔,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容