前端实现DPF在线预览的插件比较多,不过大多都不够成熟,用起来可能以为没那么好用;选了一个我的以为相对好用,适合咱们现有框架的mozilla/pdf.jscss
参考资料: mozilla/pdf.jshtml
这个库目前没有用npm安装的,直接在头部引入线上的或者下载一个就能够用了前端
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="yes" name="apple-touch-fullscreen">
<meta content="telephone=no,email=no" name="format-detection">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="stylesheet" href="./iconfont/iconfont.css">
<script src="http://res.wx.qq.com/open/js/jweixin-1.2.0.js"></script>
<script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>
</head>
<body>
<div id="appContainer"></div>
</body>
</html>
复制代码
class PDF extends React.Component {
constructor (props) {
super(props)
this.state = {
pdf: null,
scale: 1.2
}
}
getChildContext () {
return {
pdf: this.state.pdf,
scale: this.state.scale
}
}
componentDidMount () {
PDFJS.getDocument(this.props.src).then((pdf) => {
console.log(pdf)
this.setState({ pdf })
})
}
render () {
return (<div className='pdf-context'>{this.props.children}</div>)
}
}
PDF.propTypes = {
src: React.PropTypes.string.isRequired
}
PDF.childContextTypes = {
pdf: React.PropTypes.object,
scale: React.PropTypes.number
}
class Page extends React.Component {
constructor (props) {
super(props)
this.state = {
status: 'N/A',
page: null,
width: 0,
height: 0
}
}
shouldComponentUpdate (nextProps, nextState, nextContext) {
return this.context.pdf != nextContext.pdf || this.state.status !== nextState.status
}
componentDidUpdate (nextProps, nextState, nextContext) {
this._update(nextContext.pdf)
}
componentDidMount () {
this._update(this.context.pdf)
}
_update (pdf) {
if (pdf) {
this._loadPage(pdf)
} else {
this.setState({ status: 'loading' })
}
}
_loadPage (pdf) {
if (this.state.status === 'rendering' || this.state.page != null) return;
pdf.getPage(this.props.index).then(this._renderPage.bind(this))
this.setState({ status: 'rendering' })
}
_renderPage (page) {
console.log(page)
let { scale } = this.context
let viewport = page.getViewport(scale)
let { width, height } = viewport
let canvas = this.refs.canvas
let context = canvas.getContext('2d')
console.log(viewport.height, viewport.width)
canvas.width = width
canvas.height = height
page.render({
canvasContext: context,
viewport
})
this.setState({ status: 'rendered', page, width, height })
}
render () {
let { width, height, status } = this.state
return (
<div className={`pdf-page {status}`} style={{width, height}}>
<canvas ref='canvas' />
</div>
)
}
}
Page.propTypes = {
index: React.PropTypes.number.isRequired
}
Page.contextTypes = PDF.childContextTypes
class Viewer extends React.Component {
render () {
let { pdf } = this.context
let numPages = pdf ? pdf.pdfInfo.numPages : 0
let fingerprint = pdf ? pdf.pdfInfo.fingerprint : 'none'
let pages = Array.apply(null, { length: numPages })
.map((v, i) => (<Page index={i + 1} key={`${fingerprint}-${i}`}/>))
return (
<div className='pdf-viewer'>
{pages}
</div>
)
}
}
Viewer.contextTypes = PDF.childContextTypes
复制代码
最后一步就是调用这个PDF组件就能够了,这里须要改一下头部的meta[name="viewport"]的属性为可自由放大缩小,退出PDF页时须要恢复meta标签为不可手动缩放的react
class previewPDF extends React.Component {
constructor (props) {
super (props);
}
// 初始化PDF组件时改变meta为可手动缩放
componentDidMount(){
document.querySelector('meta[name="viewport"]').setAttribute("content", "width=device-width,user-scalable=yes,initial-scale=0.5,maximum-scale=1.2,minimum-scale=0.1");
}
// 组件卸载时恢复meta
componentWillUnmount(){
document.querySelector('meta[name="viewport"]').setAttribute("content", "width=device-width,user-scalable=no,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5");
window.location.reload();
}
render() {
let PDF_URL = getQueryString('pdf', this.props.location.search);
return (
<PDF src={PDF_URL}>
<Viewer />
</PDF>
);
}
}
复制代码
-------------------更新内容------------------git
因为React v15.5起,React.PropTypes已移至另外一个包中。 React.PropTypes请改用prop-types库。 prop-types的使用以下:github
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
复制代码
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export class PDF extends Component {
constructor (props) {
super(props)
this.state = {
pdf: null,
scale: 1.2
}
}
getChildContext () {
return {
pdf: this.state.pdf,
scale: this.state.scale
}
}
componentDidMount () {
PDFJS.getDocument(this.props.src).then((pdf) => {
console.log(pdf)
this.setState({ pdf })
})
}
render () {
return (<div className='pdf-context'>{this.props.children}</div>)
}
}
// PDF.propTypes = {
// src: PropTypes.string.isRequired
// }
PDF.childContextTypes = {
pdf: PropTypes.object,
scale: PropTypes.number
}
export class Page extends Component {
constructor (props) {
super(props)
this.state = {
status: 'N/A',
page: null,
width: 0,
height: 0
}
}
// shouldComponentUpdate (nextProps, nextState, nextContext) {
// return this.context.pdf != nextContext.pdf || this.state.status !== nextState.status
// }
// componentDidUpdate (nextProps, nextState, nextContext) {
// debugger
// this._update(nextContext.pdf)
// }
componentDidMount () {
this._update(this.context.pdf)
}
_update (pdf) {
if (pdf) {
this._loadPage(pdf)
} else {
this.setState({ status: 'loading' })
}
}
_loadPage (pdf) {
if (this.state.status === 'rendering' || this.state.page != null) return;
pdf.getPage(this.props.index).then(this._renderPage.bind(this))
this.setState({ status: 'rendering' })
}
_renderPage (page) {
let { scale } = this.context
let viewport = page.getViewport(scale)
let { width, height } = viewport
let canvas = this.refs.canvas
let context = canvas.getContext('2d')
canvas.width = width
canvas.height = height
page.render({
canvasContext: context,
viewport
})
this.setState({ status: 'rendered', page, width, height })
}
render () {
let { width, height, status } = this.state
return (
<div className={`pdf-page {status}`} style={{width, height}}>
<canvas ref='canvas' />
</div>
)
}
}
// Page.propTypes = {
// index: PropTypes.number.isRequired
// }
Page.contextTypes = PDF.childContextTypes
export class Viewer extends Component {
render () {
let { pdf } = this.context
let numPages = pdf ? pdf.pdfInfo.numPages : 0
let fingerprint = pdf ? pdf.pdfInfo.fingerprint : 'none'
let pages = Array.apply(null, { length: numPages })
.map((v, i) => (<Page index={i + 1} key={`${fingerprint}-${i}`}/>))
return (
<div className='pdf-viewer'>
{pages}
</div>
)
}
}
Viewer.contextTypes = PDF.childContextTypes
复制代码