react下實現一個PDF展現組件

簡介:在react的antd-pro的框架下展現本地的PDF文件

效果圖:react

clipboard.png

1、插件選取。

據說過大名鼎鼎的PDF.js,可是由於是在react框架下,因此選取了兩個可行的插件git

兩個插件都是對PDF進行的封裝。兩個插件都進行了嘗試,相對而言react-pdf功能更強大而且文檔也比較清晰,可是使用也會相對複雜一點。最後使用的是react-pdf-js這個插件。github

2、展現選擇的文件。

react-pdf-js

第一步:展現一個本地文檔。

按照官方的文檔:ajax

render() {
  let pagination = null;
  if (this.state.pages) {
    pagination = this.renderPagination(this.state.page, this.state.pages);
  }
  return (
    <div>
      <PDF
        file="test.pdf"
        onDocumentComplete={this.onDocumentComplete}
        page={this.state.page}
      />
      {pagination}
    </div>
  )
}

注意:官方文檔沒有任何說明。此處的file是一個require過來的文件。
例子:要加載一個'E:\1.pdf',那麼應該那麼配置:canvas

const PDFTest = require('E:\\1.pdf');
render() {
  let pagination = null;
  if (this.state.pages) {
    pagination = this.renderPagination(this.state.page, this.state.pages);
  }
  return (
    <div>
      <PDF
        file={PDFTest}
        onDocumentComplete={this.onDocumentComplete}
        page={this.state.page}
      />
      {pagination}
    </div>
  )
}

第二步:根據文件選擇框更改文件。

這一步被卡住過,剛開始想的是根據選擇的文件而後獲取文件的實際地址而後運用require去獲取文件,可是實現的時候發現瀏覽器的安全策略沒法讓瀏覽器獲取文件的真實路徑。
可是!咱們能夠經過建立一個URL對象去獲取文件的一個blob。使用window.URL.createObjectURL建立一個file文件,而且react-pdf-js能夠直接接受一個這樣子的文件。
部分代碼以下:瀏覽器

handleButtonOnChange = e =>{
  if (e.currentTarget.files.length === 0) return;
  const url = window.URL.createObjectURL(e.currentTarget.files[0]);
  this.setState({
    pdfTest: {
      key:url,
      file:url,
    },
  })
}
createPDF = () =>{
  const { pageNumber, numPages, pdfTest } = this.state;
  if(!pdfTest) return;
  return(
    <div>
      <div className={style.pdfContainer}>
        <PDF
          key={pdfTest.key}
          file={pdfTest.file}
          onDocumentComplete={this.onDocumentComplete}
          page={pageNumber}
          className={style.pdfView}
          width='300px'
        />
      </div>
      <p style={{float:'right'}}>第 {pageNumber} 頁  共 {numPages} 頁</p>
    </div>
  )
}
render() {
  return (
    <div id='PDFViewer'>
      <input id='id' type="file" style={{width:'200px',height:'35px'}} accept=".pdf" onChange={this.handleButtonOnChange} />
      {this.createPDF()}
    </div>
  );
}

此處還有一個坑,就是key這個值。在文檔中沒有提到這個值,而且在源代碼中也沒有怎麼出現這個值。這個key值應該是標識每一個文件的一個惟一標識,當key值不一樣的時候會從新渲染canvas。安全

如下作法不推薦:
在以前我沒發現這個以前,經過修改源碼的這個地方改成:antd

componentWillReceiveProps(newProps) {
  const {
    page,
    scale,
    file:oldfile,
    onDocumentComplete,
    cMapUrl,
    cMapPacked,
  } = this.props;
  const { pdf } = this.state;
  const { file:newfile } = newProps;
  if(newfile !== oldfile){
    PdfJsLib.GlobalWorkerOptions.workerSrc = '//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.js';
    PdfJsLib.getDocument({ url: newfile, cMapUrl, cMapPacked }).then((newPdf) => {
      this.setState({ pdf:newPdf });
      if (onDocumentComplete) {
        onDocumentComplete(newPdf._pdfInfo.numPages); // eslint-disable-line
      }
      pdf.getPage(page).then(p => this.drawPDF(p));
    });
  }else{
    if (newProps.page !== page) {
      pdf.getPage(newProps.page).then(p => this.drawPDF(p));
    }
    if (newProps.scale !== scale) {
      pdf.getPage(newProps.page).then(p => this.drawPDF(p));
    }
  }
}

手動實現了這個功能,可是這個斷定方法存在一些問題,只有再加入一個變量去判斷纔會完善,就徹底和他的key這個值同樣,可是知道key值以後就沒有再對源碼進行修改了。框架

第三筆:其餘功能。

翻頁以及跳頁:ui

handleTurnPage = e =>{
  const { pageNumber, numPages, turnPageNumber } = this.state;
  if(!numPages){
    message.warning('請先選擇PDF文件');
    return;
  }
  let newPageNumber = pageNumber;
  switch (e.target.id) {
    case 'pageUp':
      newPageNumber -= 1;
      if(newPageNumber <= 0){
        message.warning('已是第一頁');
        return;
      }
      break;
    case 'pageDown':
      newPageNumber += 1;
      if(newPageNumber > numPages){
        message.warning('已是最後一頁');
        return;
      }
      break;
    case 'numberPage':
      if(!turnPageNumber){
        message.warning('請先輸入數字');
        return;
      }else if(turnPageNumber <= 0||turnPageNumber > numPages){
        message.warning('請輸入在頁面範圍內的數字');
        return;
      }
      newPageNumber = turnPageNumber;
      break;
    default:
      break;
  }
  this.setState({
    pageNumber:newPageNumber,
  })
}
render() {
  return (
    <div id='PDFViewer'>
      <input id='id' type="file" style={{width:'200px',height:'35px'}} accept=".pdf" onChange={this.handleButtonOnChange} />
      <div style={{float:'right'}}>
        <InputNumber onChange={this.onPageNumberInputChange} style={{width:'150px'}} placeholder='輸入須要跳轉的頁' />
        <Button onClick={this.handleTurnPage} id="numberPage">確認跳轉</Button>
        <Button onClick={this.handleTurnPage} id="pageUp">上一頁</Button>
        <Button onClick={this.handleTurnPage} id="pageDown">下一頁</Button>
      </div>
      {this.createPDF()}
    </div>
  );
}

完整代碼:GitHub

react-pdf

這個插件的功能很強大,可是使用就相對而言比較複雜。官方的 複雜demo

因爲最後使用的是另外的一個插件。這裏就只寫一下踩坑記錄。

一、file參數。

在這裏file這個參數和react-pdf-js的不同,在require的時候都是同樣的,可是在轉換的時候不用建立URL對象,直接將input裏面的file傳過去便可。而且不須要key。
例子:

handleButtonOnChange = e =>{
  if (e.currentTarget.files.length === 0) return;
  this.setState({
    pdfTest: {
      file:e.currentTarget.files[0],
    },
  })
}

二、不顯示text layers

PDF存在一個問題沒法選擇裏面的文字以及連接,可是PDF.js經過在裏面添加一層文本層用於輔助選取,可是在這個插件裏面會存在一個重影,致使文字顯示效果不佳,如圖:

clipboard.png

在官方文檔中提到使用SVG能夠解決這個問題,可是SVG選擇出來是亂碼。因此在使用的時候但願屏蔽掉text layer,在文檔中也有提到,在page中設置。

以上是全部內容。

相關文章
相關標籤/搜索