前端实现DPF在线预览的插件比较多,不过大多都不够成熟,用起来可能觉得没那么好用;选了一个个人觉得相对好用,适合我们现有框架的mozilla/pdf.js
头部引入mozilla/pdf.js的库
这个库目前没有用npm安装的,直接在头部引入线上的或者下载一个就可以用了
复制代码
封装一个PDF组件,直接复制粘贴这段代码就可以
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 (
}
}
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 (
)
}
}
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) => ())
return (
{pages}
)
}
}
Viewer.contextTypes = PDF.childContextTypes
复制代码
最后一步就是调用这个PDF组件就可以了,这里需要改一下头部的meta[name="viewport"]的属性为可自由放大缩小,退出PDF页时需要恢复meta标签为不可手动缩放的
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 (
);
}
}
复制代码
-------------------更新内容------------------
React.PropTypes的问题
由于React v15.5起,React.PropTypes已移至另一个包中。
React.PropTypes请改用prop-types库。
prop-types的使用如下:
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
Hello, {this.props.name}
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
复制代码
更新后的PDF组件
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 (
}
}
// 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 (
)
}
}
// 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) => ())
return (
{pages}
)
}
}
Viewer.contextTypes = PDF.childContextTypes
复制代码