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中设置。

以上是全部内容。

相关文章
相关标签/搜索