React实现打印功能

46次阅读

共计 8990 个字符,预计需要花费 23 分钟才能阅读完成。

一、需求分析:
环境:react,antd,antd-pro 将选中的数据进行打印,可以自定义分页的大小。由于打印的列等多个因素,导致如果写成组件在使用的时候依旧会改变源码,所以采用了写成页面的方式,
二、实现需求:
1、数据传值
进行传值的时候,刚开始使用的是在通过 this.props.location 进行传值,但是这样数据被写死了,导致再次进入页面的时候无法更新打印的值。最后采用了一个全局的 model 进行实现的传值。
2、表格生成
分为四部分进行生成,分别是标题、表头、表格、表尾。其中表头,表尾因为需求的原因写死。以下为代码:
createTitle = (title)=>(
<div>
<h1 style={styleObj.title}>{title}</h1>
</div>
)

createHeader = (headerData)=>{
headerData = [
{
orderID:’ 订单编号 ’,
value:’P201901020002′,
},{
people:’ 采购人员 ’,
value:’xxx’,
},{
time:’ 采购时间 ’,
value:’2019 年 01 月 01 日 ’,
}
];
return (
<table>
<tbody style={styleObj.header}>
<tr>
<th> 订单编号:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”P201901020002″ />
</th>
</tr>
<tr>
<th> 采购员:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”xxx” />
</th>
<th> 采购时间:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”2019 年 01 月 01 日 ” />
</th>
</tr>
</tbody>
</table>
)
}

createForm = (printCol,printData)=>(
<table style={styleObj.printTable}>
<tbody>
{
(
<tr style={styleObj.printTableTr}>
{printCol.map(item=><th style={{…styleObj[item.key],…styleObj.printTableTh}}><div>{item.name}</div></th>)}
</tr>
)
}
{
printData.map(item=> (
<tr style={styleObj.printTableTr}>
{Object.keys(item).map(i => <th style={styleObj.printTableTh}>{item[i]}</th>)}
</tr>
)
)
}
</tbody>
</table>
)

createFooter = (footerData)=>{
return (
<table>
<tbody style={styleObj.footer}>
<tr>
<th> 供应商(签字)</th>
<th>
<div style={styleObj.footerSpace} />
</th>
<th colSpan=”4″>
<input style={styleObj.printInputFooter} />
</th>
<th> 库管员(签字)</th>
<th>
<div style={styleObj.footerSpace} />
</th>
<th colSpan=”4″>
<input style={styleObj.printInputFooter} />
</th>
<th>{` 第 ${footerData.current} 页 `}</th>
<th>{` 共 ${footerData.total} 页 `}</th>
</tr>
</tbody>
</table>
)
}
createPrintArea = (printCol)=>{
const {printGroupData} = this.state;
return (
printGroupData.map((item,index)=>{
if(item.length){
return (
<div style={styleObj.printArea}>
{this.createTitle(‘xxxxxxx 公司 xxx 单 ’)}
{this.createHeader(‘asd’)}
{this.createForm(printCol,item)}
{this.createFooter({current:index+1,total:printGroupData.length})}
</div>
)
}
})
)
}
最主要的是 CSS 的调整,因为之后的打印需求将所有的 CSS 内联:以下为 css:
export const styleObj = {
printArea:{
width: ‘500px’,
fontSize: ’12px’,
align:’center’
},
printInput:{
fontWeight:’bold’,
border: ‘none’,
},
title:{
textAlign: ‘center’,
fontSize: ’15px’,
fontWeight: ‘700’,
},
header:{
fontWeight:’bold’,
fontSize: ’12px’,
},
printTable:{
fontSize: ’12px’,
fontWeight: ‘700’,
color: ‘black’,
border: ‘1px black’,
borderCollapse: ‘collapse’,
textAlign: ‘center’,
},
printTableTh:{
padding: ‘4px’,
border: ‘1px solid black’,
textAlign: ‘center’,
},
printTableTr:{
textAlign:’center’,
padding: ‘4px’,
border: ‘1px solid black’,
},
number:{
width: ’60px’,
},
goodsName:{
width: ‘180px’,
},
unitName:{
width: ’75px’,
},
specifications:{
width: ’90px’,
},
goodsType:{
width: ’90px’,
},
footer:{
fontSize:’12px’,
},
footerSpace:{
width: ’20px’,
display: ‘block’,
},
printInputFooter:{
fontWeight:’bold’,
border:’none’,
width: ’85px’,
},
};
3、实现分页
分页即将数据进行分割,然后每次生成表格的时候将分割后的每个表格数据依次传入表格生成函数,从而生成全部表格。分页函数:
// 传入的数据为:分页的大小,需要分页的数据。
page = (pageNumber,printData)=>{
const printDataBack = printData.concat();
const printGroupData = [];
while(printDataBack.length >= pageNumber){
let tempGroup = [];
tempGroup = printDataBack.splice(0,pageNumber);
printGroupData.push(tempGroup);
}
if(printDataBack.length){
printGroupData.push(printDataBack);
}
printGroupData.forEach((item)=>{
item.forEach((i,index)=>{
i.number = index+1;
})
});
return printGroupData;
}
注意:解构出来的数据是引用,需要进行备份。设置一个 input 框以及一个按钮,input 框用于输入分页的数字,再点击按钮以及第一次进入页面的时候进行分页。
4、实现打印
实现方法一(不推荐):
直接在本页面进行刷新
优点:css 不用内嵌。缺点:导致本页面刷新,某些数据丢失。
实现方法:直接获取到需要打印的区域,然后将本页面的 innerHTML 设置为获取的区域,然后调用系统的 print,最后调用 reload
代码:
print = () => {
window.document.body.innerHTML = window.document.getElementById(‘billDetails’).innerHTML;
window.print();
window.location.reload();
}
实现方法二:
打开一个页面进行打印
优点:打印不在关乎本页面的业务缺点:CSS 需要内联代码:
handlePrint = () => {
const win = window.open(”,’printwindow’);
win.document.write(window.document.getElementById(‘printArea’).innerHTML);
win.print();
win.close();
}
三、完整代码
以下为完整代码:index.js
import React, {PureComponent} from ‘react’;
import {connect} from ‘dva’;
import {
Row,
Button,
Col,
Card,
Form,
message,
InputNumber,
} from ‘antd’;
import PageHeaderWrapper from ‘@/components/PageHeaderWrapper’;
import {styleObj} from ‘./style’;

@Form.create()
@connect(({print}) => ({
print,
}))
class PrintTable extends PureComponent {
state = {
printData:[],
printCol:[],
pageNumber:10,
printGroupData:[],
}

componentDidMount() {
const printCol = [
{
key:’number’,
name:’ 序号 ’,
},{
key:’goodsName’,
name:’ 商品名称 ’,
},{
key:’goodsType’,
name:’ 商品类型 ’,
},{
key:’unitName’,
name:’ 单位 ’,
},{
key:’specifications’,
name:’ 规格 ’,
}];
const printData = [];
const {pageNumber} = this.state;
const {print:{ payload:{formPrintData} } } = this.props;
formPrintData.forEach((i,index)=>{
const colData = {};
printCol.forEach(j=>{
colData[j.key] = i[j.key];
})
colData.number = index+1;
printData.push(colData);
});
const printGroupData = this.page(pageNumber,printData);
this.setState({
printData,
printCol,
printGroupData,
})
}

componentWillReceiveProps(nextProps){
const printCol = [
{
key:’number’,
name:’ 序号 ’,
},{
key:’goodsName’,
name:’ 商品名称 ’,
},{
key:’goodsType’,
name:’ 商品类型 ’,
},{
key:’unitName’,
name:’ 单位 ’,
},{
key:’specifications’,
name:’ 规格 ’,
}];
const printData = [];
const {pageNumber} = this.state;
const {print:{ payload:{formPrintData} } } = nextProps;
formPrintData.forEach((i,index)=>{
const colData = {};
printCol.forEach(j=>{
colData[j.key] = i[j.key];
})
colData.number = index+1;
printData.push(colData);
});
const printGroupData = this.page(pageNumber,printData);
this.setState({
printData,
printCol,
printGroupData,
})
}

createTitle = (title)=>(
<div>
<h1 style={styleObj.title}>{title}</h1>
</div>
)

createHeader = (headerData)=>{
headerData = [
{
orderID:’ 订单编号 ’,
value:’P201901020002′,
},{
people:’ 采购人员 ’,
value:’xxx’,
},{
time:’ 采购时间 ’,
value:’2019 年 01 月 01 日 ’,
}
];
return (
<table>
<tbody style={styleObj.header}>
<tr>
<th> 订单编号:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”P201901020002″ />
</th>
</tr>
<tr>
<th> 采购员:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”xxx” />
</th>
<th> 采购时间:</th>
<th colSpan=”7″>
<input style={styleObj.printInput} value=”2019 年 01 月 01 日 ” />
</th>
</tr>
</tbody>
</table>
)
}

createForm = (printCol,printData)=>(
<table style={styleObj.printTable}>
<tbody>
{
(
<tr style={styleObj.printTableTr}>
{printCol.map(item=><th style={{…styleObj[item.key],…styleObj.printTableTh}}><div>{item.name}</div></th>)}
</tr>
)
}
{
printData.map(item=> (
<tr style={styleObj.printTableTr}>
{Object.keys(item).map(i => <th style={styleObj.printTableTh}>{item[i]}</th>)}
</tr>
)
)
}
</tbody>
</table>
)

createFooter = (footerData)=>{
return (
<table>
<tbody style={styleObj.footer}>
<tr>
<th> 供应商(签字)</th>
<th>
<div style={styleObj.footerSpace} />
</th>
<th colSpan=”4″>
<input style={styleObj.printInputFooter} />
</th>
<th> 库管员(签字)</th>
<th>
<div style={styleObj.footerSpace} />
</th>
<th colSpan=”4″>
<input style={styleObj.printInputFooter} />
</th>
<th>{` 第 ${footerData.current} 页 `}</th>
<th>{` 共 ${footerData.total} 页 `}</th>
</tr>
</tbody>
</table>
)
}

handlePrint = () => {
const win = window.open(”,’printwindow’);
win.document.write(window.document.getElementById(‘printArea’).innerHTML);
win.print();
win.close();
}

createPrintArea = (printCol)=>{
const {printGroupData} = this.state;
return (
printGroupData.map((item,index)=>{
if(item.length){
return (
<div style={styleObj.printArea}>
{this.createTitle(‘xxxxxxx 公司 xxx 单 ’)}
{this.createHeader(‘asd’)}
{this.createForm(printCol,item)}
{this.createFooter({current:index+1,total:printGroupData.length})}
</div>
)
}
})
)
}

handlePage = ()=>{
const {pageNumber, printData} = this.state;
if(pageNumber <= 0){
message.warning(‘ 输出正确的分页 ’);
return;
}
this.setState({
printGroupData:this.page(pageNumber, printData)
})
}

page = (pageNumber,printData)=>{
const printDataBack = printData.concat();
const printGroupData = [];
while(printDataBack.length >= pageNumber){
let tempGroup = [];
tempGroup = printDataBack.splice(0,pageNumber);
printGroupData.push(tempGroup);
}
if(printDataBack.length){
printGroupData.push(printDataBack);
}
printGroupData.forEach((item)=>{
item.forEach((i,index)=>{
i.number = index+1;
})
});
return printGroupData;
}

onChange = (value)=>{
this.setState({
pageNumber:value,
})
}

render() {
const {printCol, printData} = this.state;
return (
<PageHeaderWrapper title=” 查询表格 ”>
<Card>
<Row>
<Col span={6}>
<Row>
<Col span={12}>
<InputNumber onChange={this.onChange} placeholder=’ 输入自定义分页数量 ’ style={{width:’100%’}}/>
</Col>
<Button onClick={this.handlePage}> 确认分页 </Button>
</Row>
<Row>
<Button onClick={this.handlePrint} type=’primary’> 打印 </Button>
</Row>
</Col>
<Col span={12}>
<div id=’printArea’>
<div style={styleObj.printArea}>
{printCol.length&&printData.length? this.createPrintArea(printCol):null}
</div>
</div>
</Col>
</Row>
</Card>
</PageHeaderWrapper>
);
}
}

export default PrintTable;
style.js
export const styleObj = {
printArea:{
width: ‘500px’,
fontSize: ’12px’,
align:’center’
},
printInput:{
fontWeight:’bold’,
border: ‘none’,
},
title:{
textAlign: ‘center’,
fontSize: ’15px’,
fontWeight: ‘700’,
},
header:{
fontWeight:’bold’,
fontSize: ’12px’,
},
printTable:{
fontSize: ’12px’,
fontWeight: ‘700’,
color: ‘black’,
border: ‘1px black’,
borderCollapse: ‘collapse’,
textAlign: ‘center’,
},
printTableTh:{
padding: ‘4px’,
border: ‘1px solid black’,
textAlign: ‘center’,
},
printTableTr:{
textAlign:’center’,
padding: ‘4px’,
border: ‘1px solid black’,
},
number:{
width: ’60px’,
},
goodsName:{
width: ‘180px’,
},
unitName:{
width: ’75px’,
},
specifications:{
width: ’90px’,
},
goodsType:{
width: ’90px’,
},
footer:{
fontSize:’12px’,
},
footerSpace:{
width: ’20px’,
display: ‘block’,
},
printInputFooter:{
fontWeight:’bold’,
border:’none’,
width: ’85px’,
},
};

正文完
 0