当前位置: 首页 > news >正文

react项目中实现打印预览功能

最近项目中,前端采用react+antd+dva的组合,
今天有一个新需求,
需要在后台管理系统中实现 点击打印 完成指定页面的打印功能。

我们道浏览器带有打印功能的实现,window.print()。

然而,在react中是没有dom节点的,不过我们也是可以转为dom节点的。就是在需要打印的内容部分节点添加一个ID
在这里插入图片描述
  只不过,这样打印出来的内容是没有带样式的,因为一般css文件并不会写到行内去,所以在生成html的文件字符串时,里面没有样式信息,在打印时就会布局混乱。
要想打印出来的效果与网页上显示的效果一致,就需要在生成html的文件字符串时,带上样式信息。

方法1:把样式信息写在行内
在文件信息不复杂时,可以写在行内

方法2:使用react-inline-css
使用这个npm包,可以在配置后把样式自动添加到行内

网页效果图:横版效果
在这里插入图片描述

打印预览竖版图:

在这里插入图片描述
代码下:

	import React, { PureComponent } from 'react';
	import moment from 'moment';
	import { connect } from 'dva';
	import { 
	  Card, 
	  Button, 
	  Form, 
	  Table, 
	  message,
	 } from 'antd';
	import styles from './Funds.less';
	
	@connect(({ finance, loading }) => ({
	  finance,
	  loading: loading.models.list,
	}))
	
	@Form.create()
	export default class LoanSettleMent extends PureComponent {
	  constructor(props) {
	    super(props);
	    this.state = {
	      loading: true,
	    };
	  }

	  componentDidMount() {
	    const code = !isEmptyObject(this.props.match) ? this.props.match.params.id : 0;
	    this.statisticalInfo({ receiptsCode: code });
	  }
	
	  // 结算单列表详情
	  statisticalInfo(params) {
	    this.props.dispatch({
	      type: 'finance/statisticalInfo',
	      payload: params,
	    }).then(() => {
	      this.setState({
	        loading: false,
	      })
	    });
	  }

	  // 撤销操作
	  fetchRevocation(params) {
	    this.props
	      .dispatch({
	        type: 'finance/fetchRevocation',
	        payload: params,
	      })
	      .then(() => {
	        const { finance: { revocationData } } = this.props;
	        const { code } = revocationData;
	        if (code === 200) {
	          message.info('撤销货款单成功!').then(() => {
	            window.location.href = '/funds/loansettlement';
	          });
	        } else {
	          message.info('撤销货款单失败!');
	        }
	      });
	  }

	  // 撤销
	  cancer = () => {
	    const code = !isEmptyObject(this.props.match) ? this.props.match.params.id : 0;
	    this.fetchRevocation({
	      receiptsCode: code,
	    });
	  };

	  // 返回
	  back = () => {
	    window.history.back();
	  };

	  // 打印
	  print(){
	    window.document.body.innerHTML = window.document.getElementById('billDetails').innerHTML;  
	    window.print(); 
	    window.location.reload();
	  }

	  render() {
	    const { finance: { statisticalInfo }, loading } = this.props;
	    let data = [],
	        createName,
	        createTime;
	    if (statisticalInfo && !Array.isArray(statisticalInfo)) {
	      data = statisticalInfo;
	      createName = statisticalInfo.createName;
	      createTime = statisticalInfo.createTime;
	    }

	    if (statisticalInfo != undefined) {
	      data = statisticalInfo.goodsVos;
	    }
		
	    let _data = [],
	        receiptsCode;
	    if (statisticalInfo && !Array.isArray(statisticalInfo)) {
	      _data = statisticalInfo;
	      receiptsCode = statisticalInfo.receiptsCode;
	    }
	    const { supplierName, carNo, stallName, startTime, endTime, enable } = _data;

    const len = data.length;

    const columns = [
      {
        title: '品种',
        dataIndex: 'attrName',
        align: 'center',
      },
      {
        title: '销售货款',
        dataIndex: 'goodsAmount',
        align: 'left',
        render: (text, record, index) => {
          const { goodsAmount, goodsPaymentStr } = record;
          const type = goodsPaymentStr !== null ? goodsPaymentStr.split('负').length : -1;
          if (index < len - 1) {
            return <span>{goodsAmount ? Yuan(goodsAmount, 2) : ''}</span>;
          }
          return {
            children:
              type == 2 ? (
                <span className={styles.neg}>{goodsPaymentStr}</span>
              ) : (
                <span className={styles.bold}>{goodsPaymentStr}</span>
              ),
            props: {
              colSpan: 7,
            },
          };
        },
      },
      {
        title: '件数',
        dataIndex: 'number',
        align: 'center',
        render: (text, record, index) => {
          const { number } = record;
          if (index < len - 1) {
            return <span>{number ? number : ''}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
      {
        title: '重量',
        dataIndex: 'weight',
        align: 'center',
        render: (text, record, index) => {
          const { weight } = record;
          if (index < len - 1) {
            return <span>{weight ? weight : ''}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
      {
        title: '平均售价',
        dataIndex: 'averageAmount',
        align: 'center',
        render: (text, record, index) => {
          const { averageAmount } = record;
          if (index < len - 1) {
            return <span>{averageAmount ? Yuan(averageAmount, 2) : ''}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
      {
        title: '平均重量',
        dataIndex: 'averageWeight',
        align: 'center',
        render: (text, record, index) => {
          const { averageWeight } = record;
          if (index < len - 1) {
            return <span>{averageWeight ? averageWeight : ''}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
      {
        title: '费用类型',
        dataIndex: 'type',
        align: 'center',
        render: (text, record, index) => {
          const { type } = record;
          if (index < len - 1) {
            return <span>{type}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
      {
        title: '扣款金额',
        dataIndex: 'amount',
        align: 'center',
        render: (text, record, index) => {
          const { amount } = record;
          if (index < len - 1) {
            return <span>{amount !== null ? Yuan(amount, 2) : ''}</span>;
          }
          return {
            children: '',
            props: {
              colSpan: 0,
            },
          };
        },
      },
    ];

    return (
      <PageHeaderLayout>
        <div className={styles.billDetails} id={'billDetails'}>
          <Card
            bordered={false}
            title=""
          >
            <div className={styles.paymentbill}>
              <div style={{display: 'flex', height: '60px', lineHeight: '60px'}}>
                <h1 style={{flex: 1, textAlign: 'center'}}>{stallName}</h1>
                <span style={{position: 'absolute', right: '10px', color: '#FF6666', fontWeight: '600'}}>{`NO:${receiptsCode !== undefined ? receiptsCode : ''}`}</span>
              </div>

              <div style={{display: 'flex'}}>
                <h2 style={{flex: 1, textAlign: 'center'}}>商品销售车次结算单</h2>
                <div style={{position: 'absolute', right: '10px'}}>
                  <Button type="primary" onClick={this.cancer} disabled={!enable} style={{marginRight: '5px'}}>
                    撤销
                  </Button>
                  <Button onClick={this.print.bind(this)} style={{marginRight: '5px'}}>打印</Button>
                  <Button type="primary" onClick={this.back} style={{marginRight: '5px'}}>
                    返回
                  </Button>
                </div>
              </div>

              <div style={{display: 'flex'}}>
                <h3 style={{flex: 1, textAlign: 'left'}}>{`货老板:${supplierName !== undefined ? supplierName : ''} ${
                  carNo !== undefined ? fixedZeroTo4Bit(carNo, 4) : 0
                }车`}
                </h3>
                <h3 style={{flex: 1}}>{`到货时间:${moment(startTime).format('YYYY-MM-DD')}`}</h3>
                <h3 style={{flex: 1}}>{`售罄时间:${moment(endTime).format('YYYY-MM-DD')}`}</h3>
              </div>

              <img src={watermark} hidden={enable} style={{position: 'absolute', width: '100px', height: '100px', top: '120px', right: '80px',zIndex: 100}} />
            </div>
          </Card>
          <Card
            bordered={false}
            title=""
            bodyStyle={{ padding: '0 16px' }}
          >
            <Table
              dataSource={data}
              columns={columns}
              bordered
              pagination={false}
              loading={this.state.loading}
            />
          </Card>
          <Card style={{ border: 0 }}>
            <div style={{display: 'flex'}}>
              <h3 style={{flex: 1}}>{`结算人:${createName !== undefined ? createName : ''}`}</h3>
              <h3 style={{flex: 1, textAlign: 'right'}}>{`结算时间:${moment(createTime).format(
                'YYYY-MM-DD'
              )}`}</h3>
            </div>
          </Card>
        </div>
      </PageHeaderLayout>
    );
  }
}

一般直接使用window.print();是直接打印了整个页面,但只打印其中的一部分时就需要一些方法了

1、在页面的代码头部处加入JavaScript:

<script language=javascript>

	function doPrint() { 
		bdhtml = window.document.body.innerHTML; 
		sprnstr = "<!--startprint-->"; //开始打印标识字符串有17个字符
		eprnstr = "<!--endprint-->"; //结束打印标识字符串
		prnhtml = bdhtml.substr(bdhtml.indexOf(sprnstr)+17); //从开始打印标识之后的内容
		prnhtmlstr = prnhtml.substring(0,prnhtml.indexOf(eprnstr)); //截取开始标识和结束标识之间的内容
		window.document.body.innerHTML = prnhtmlstr ; //把需要打印的指定内容赋给body.innerHTML
		window.print(); //调用浏览器的打印功能打印指定区域
		window.document.body.innerHTML = bdhtml;//重新给页面内容赋值;
	}
</script>

2、在页面正文处加上<!–startprint–>与<!–endprint–>标识。

也就是在需要用户打印保存的正文所对应的html处附加上。同时,如果采用小偷程序获得远程数据并需打印,可将此等数据置于该定义标签之内即可。

3、截取内容部分已完成,现在加个“打印”的链接:

要打印的内容在
<!–startprint–>
	startprint与endprint之间的区域
<!–endprint–>里。
添加打印链接事件

<a href="javascript:;" onClick="doPrint()">打印</a>  

相关文章:

  • easyUI loyout tabs自适应宽度
  • react封装一个打印功能
  • 在linux环境下编译C++ 程序
  • react项目中,在tab列表上展示某个字段以 数组形式 展示
  • Spark Streaming官方文档学习--下
  • Vue 判断两个时间选择框的校验element 。开始时间不能大于结束时间
  • 为什么不能访问django自带的索引页
  • SSIS 数据类型和类型转换
  • Vue,列表展示。多个字段拼接展示
  • Swift开发:NSLayoutConstraint纯代码实现自动布局-初级篇
  • react中的 Modal.confirm
  • 数据挖掘之决策树ID3算法(C#实现)
  • 【一小时入门】webpack 入门指南
  • Vue中 beforeRouteLeave离开路由之前要执行的操作
  • AF3.1.0简单二次封装
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • 【5+】跨webview多页面 触发事件(二)
  • 【RocksDB】TransactionDB源码分析
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • magento2项目上线注意事项
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • tweak 支持第三方库
  • TypeScript迭代器
  • 二维平面内的碰撞检测【一】
  • 反思总结然后整装待发
  • 分布式事物理论与实践
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 学习JavaScript数据结构与算法 — 树
  • 【运维趟坑回忆录】vpc迁移 - 吃螃蟹之路
  • 移动端高清、多屏适配方案
  • ​configparser --- 配置文件解析器​
  • ​MySQL主从复制一致性检测
  • #Linux(make工具和makefile文件以及makefile语法)
  • #Lua:Lua调用C++生成的DLL库
  • #pragma pack(1)
  • #控制台大学课堂点名问题_课堂随机点名
  • (06)金属布线——为半导体注入生命的连接
  • (1)SpringCloud 整合Python
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (arch)linux 转换文件编码格式
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (附源码)ssm高校社团管理系统 毕业设计 234162
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (六)c52学习之旅-独立按键
  • (七)Java对象在Hibernate持久化层的状态
  • (转)Windows2003安全设置/维护
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转载)从 Java 代码到 Java 堆
  • *上位机的定义
  • .cn根服务器被攻击之后
  • .net 中viewstate的原理和使用