繁体   English   中英

如何在单击按钮时打印 React 组件?

[英]How to print React component on click of a button?

如何在单击按钮时只打印一个组件。

我知道这个解决方案:

window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
$('.print_frame').remove();

但是 React 不想使用框架。

有什么解决办法吗? 谢谢你。

客户端有两种解决方案。 一个是像你发布的框架。 您可以使用 iframe:

var content = document.getElementById("divcontents");
var pri = document.getElementById("ifmcontentstoprint").contentWindow;
pri.document.open();
pri.document.write(content.innerHTML);
pri.document.close();
pri.focus();
pri.print();

这期望这个 html 存在

<iframe id="ifmcontentstoprint" style="height: 0px; width: 0px; position: absolute"></iframe>

另一种解决方案是使用媒体选择器,并在media="print"样式上隐藏您不想打印的所有内容。

<style type="text/css" media="print">
   .no-print { display: none; }
</style>

最后一种方式需要在服务器上进行一些工作。 您可以将所有 HTML+CSS 发送到服务器,并使用众多组件之一来生成 PDF 等可打印文档。 我已经尝试过使用 PhantomJs 进行设置。

我正在寻找一个简单的包来完成同样的任务并且没有找到任何东西所以我创建了https://github.com/gregnb/react-to-print

你可以像这样使用它:

 <ReactToPrint
   trigger={() => <a href="#">Print this out!</a>}
   content={() => this.componentRef}
 />
 <ComponentToPrint ref={el => (this.componentRef = el)} />

您必须在 CSS 中使用@media print {}设置打印输出的样式,但简单的代码是:

export default class Component extends Component {

    print(){
        window.print();
    }


  render() {

  ...
  <span className="print"
              onClick={this.print}>
    PRINT
    </span>

  } 
}

希望这会有所帮助!

2017 年 6 月 19 日,这对我来说非常完美。

import React, { Component } from 'react'

class PrintThisComponent extends Component {
  render() {
    return (
      <div>
        <button onClick={() => window.print()}>PRINT</button>
        <p>Click above button opens print preview with these words on page</p>
      </div>
    )
  }
}

export default PrintThisComponent

如果您希望打印您已经可以访问的特定数据,无论是来自商店、AJAX 还是其他地方,您都可以利用我的库 react-print。

https://github.com/captray/react-print

它使创建打印模板变得更加容易(假设您已经依赖于 react)。 您只需要适当地标记您的 HTML。

这个 ID 应该在你的实际 DOM 树中添加到更高的位置,以排除除了下面的“打印安装”之外的所有内容。

<div id="react-no-print"> 

这是您的 react-print 组件将安装和包装您创建的模板的地方:

<div id="print-mount"></div>

一个示例如下所示:

var PrintTemplate = require('react-print');
var ReactDOM = require('react-dom');
var React = require('react');

var MyTemplate = React.createClass({
    render() {
        return (
            <PrintTemplate>
                <p>Your custom</p>
                <span>print stuff goes</span>
                <h1>Here</h1>
            </PrintTemplate>
        );
    }
});

ReactDOM.render(<MyTemplate/>, document.getElementById('print-mount'));

值得注意的是,您可以在模板中创建新的或利用现有的子组件,并且所有内容都应该可以很好地打印。

Emil Ingerslev 提供的解决方案工作正常,但 CSS 未应用于输出。 在这里,我找到了Andrewlimaza给出的一个很好的解决方案。 它打印给定 div 的内容,因为它使用 window 对象的 print 方法,所以 CSS 不会丢失。 而且也不需要额外的 iframe。

var printContents = document.getElementById("divcontents").innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;

更新 1 :在 chrome/firefox/opera/edge 中存在异常行为,执行此代码后打印或其他按钮停止工作。

更新 2 :给出的解决方案在上面的评论链接中:

.printme { display: none;}
@media print { 
    .no-printme  { display: none;}
    .printme  { display: block;}
}

<h1 class = "no-printme"> do not print this </h1>    
<div class='printme'>
  Print this only 
</div>    
<button onclick={window.print()}>Print only the above div</button>

首先要感谢@emil-ingerslev 的出色答案。 我对其进行了测试,并且效果很好。 有两件事我想改进。

  1. 我不喜欢<iframe id="ifmcontentstoprint" style="height: 0px; width: 0px; position: absolute"></iframe>已经在 dom 树中。
  2. 我想创造一种使其可重复使用的方法。

我希望这能让其他人开心,并挽救几分钟的生命。 现在去多花点时间,为某人做点好事。

function printPartOfPage(elementId, uniqueIframeId){
    const content = document.getElementById(elementId)
    let pri
    if (document.getElementById(uniqueIframeId)) {
        pri = document.getElementById(uniqueIframeId).contentWindow
    } else {
        const iframe = document.createElement('iframe')
        iframe.setAttribute('title', uniqueIframeId)
        iframe.setAttribute('id', uniqueIframeId)
        iframe.setAttribute('style', 'height: 0px; width: 0px; position: absolute;')
        document.body.appendChild(iframe)
        pri = iframe.contentWindow
    }
    pri.document.open()
    pri.document.write(content.innerHTML)
    pri.document.close()
    pri.focus()
    pri.print()
}

编辑 2019-7-23:在使用更多之后,这确实有缺点,它不能完美地渲染反应组件。 当样式是内联时,这对我有用,但在样式组件或其他一些情况下处理时不起作用。 如果我想出一个万无一失的方法,我会更新。

只是分享对我有用的东西,因为其他人可能会觉得它有用。 我有一个模态,只是想打印模态的正文,它可能是纸上的几页。

我尝试的其他解决方案只打印了一页,并且只打印了屏幕上的内容。 埃米尔接受的解决方案对我有用:

https://stackoverflow.com/a/30137174/3123109

这就是组件最终的样子。 它打印模态正文中的所有内容。

import React, { Component } from 'react';
import {
    Button,
    Modal,
    ModalBody,
    ModalHeader
} from 'reactstrap';

export default class TestPrint extends Component{
    constructor(props) {
        super(props);
        this.state = {
            modal: false,
            data: [
                'test', 'test', 'test', 'test', 'test', 'test', 
                'test', 'test', 'test', 'test', 'test', 'test', 
                'test', 'test', 'test', 'test', 'test', 'test',
                'test', 'test', 'test', 'test', 'test', 'test',
                'test', 'test', 'test', 'test', 'test', 'test',
                'test', 'test', 'test', 'test', 'test', 'test',
                'test', 'test', 'test', 'test', 'test', 'test',
                'test', 'test', 'test', 'test', 'test', 'test'            
            ]
        }
        this.toggle = this.toggle.bind(this);
        this.print = this.print.bind(this);
    }

    print() {
        var content = document.getElementById('printarea');
        var pri = document.getElementById('ifmcontentstoprint').contentWindow;
        pri.document.open();
        pri.document.write(content.innerHTML);
        pri.document.close();
        pri.focus();
        pri.print();
    }

    renderContent() {
        var i = 0;
        return this.state.data.map((d) => {
            return (<p key={d + i++}>{i} - {d}</p>)
        });
    }

    toggle() {
        this.setState({
            modal: !this.state.modal
        })
    }

    render() {
        return (
            <div>
                <Button 
                    style={
                        {
                            'position': 'fixed',
                            'top': '50%',
                            'left': '50%',
                            'transform': 'translate(-50%, -50%)'
                        }
                    } 
                    onClick={this.toggle}
                >
                    Test Modal and Print
                </Button>         
                <Modal 
                    size='lg' 
                    isOpen={this.state.modal} 
                    toggle={this.toggle} 
                    className='results-modal'
                >  
                    <ModalHeader toggle={this.toggle}>
                        Test Printing
                    </ModalHeader>
                    <iframe id="ifmcontentstoprint" style={{
                        height: '0px',
                        width: '0px',
                        position: 'absolute'
                    }}></iframe>      
                    <Button onClick={this.print}>Print</Button>
                    <ModalBody id='printarea'>              
                        {this.renderContent()}
                    </ModalBody>
                </Modal>
            </div>
        )
    }
}

注意:但是,我很难让样式反映在iframe中。

完美解决方案:

class PrintThisComponent extends Component {
  render() {
    return (
      <div>
      <button className="btn btn-success btn-lg"
        onClick={() => window.print()}>
        PRINT
      </button>
      </div>
    )
  }
}
export default PrintThisComponent;

只需在 React 文件中的任何地方执行以下操作:

import PrintThisComponent from 'the file having above code';

<PrintThisComponent />

如果任何人仍然对打印组件有问题,请使用此库https://www.npmjs.com/package/react-to-print

这是怎么回事! 我做了这个......也许它可以帮助某人

它将等待加载打印,这很神奇...不要忘记更改 CSS 链接


    /**
     * PRINT A DIV ELEMENT
     * @param {HTMLDivElement} div
     */
    function print(div) {
        let innerHTML = `<!DOCTYPE html>
        <html lang="pt-BR">
        <head>   
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
        <link href="/css/app.css" rel="stylesheet" />
        </head>
        <body>`;
        innerHTML += div.innerHTML + "</body></html>";
        console.log(innerHTML);
        let fakeIFrame = window.document.createElement("iframe");
        document.body.appendChild(fakeIFrame);
        let fakeContent = fakeIFrame.contentWindow;
        fakeContent.document.open();
        fakeContent.document.write(innerHTML);
        fakeContent.document.close();
        fakeContent.focus();
        fakeIFrame.addEventListener("load", () => {
            fakeContent.print();
        });
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM