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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30135387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 04:43:22  来源:igfitidea点击:

How to print React component on click of a button?

javascriptreactjs

提问by AndryName

How can I print only one component on click of a button.

如何通过单击按钮仅打印一个组件。

I know this solution:

我知道这个解决方案:

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

But React doesn't want to work with a frame.

但是 React 不想使用框架。

Any solutions? Thank you.

任何解决方案?谢谢你。

回答by Emil Ingerslev

There is kind of two solutions on the client. One is with frames like you posted. You can use an iframe though:

客户端有两种解决方案。一种是像你张贴的框架。不过,您可以使用 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();

This expects this html to exist

这期望此 html 存在

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

The other solution is to use the media selector and on the media="print"styles hide everything you don't want to print.

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

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

Last way requires some work on the server. You can send all the HTML+CSS to the server and use one of many components to generate a printable document like PDF. I've tried setups doing this with PhantomJs.

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

回答by Clay_F

On 6/19/2017 This worked perfect for me.

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

回答by Sara Inés Calderón

You'll have to style your printout with @media print {}in the CSS but the simple code is:

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

export default class Component extends Component {

    print(){
        window.print();
    }


  render() {

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

  } 
}

Hope that's helpful!

希望这有帮助!

回答by captray

If you're looking to print specific data that you already have access to, whether it's from a Store, AJAX, or available elsewhere, you can leverage my library react-print.

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

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

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

It makes creating print templates much easier (assuming you already have a dependency on react). You just need to tag your HTML appropriately.

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

This ID should be added higher up in your actual DOM tree to exclude everything except the "print mount" below.

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

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

This is where your react-print component will mount and wrap your template that you create:

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

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

An example looks something like this:

一个例子看起来像这样:

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'));

It's worth noting that you can create new or utilize existing child components inside of your template, and everything should render fine for printing.

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

回答by Gregory Nowakowski

I was looking for a simple package that would do this very same task and did not find anything so I created https://github.com/gregnb/react-to-print

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

You can use it like so:

你可以像这样使用它:

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

回答by Stuart Casarotto

First want to credit @emil-ingerslev for an awesome answer. I tested it and it worked perfectly. There were two things however I wanted to improve.

首先要感谢@emil-ingerslev 提供了一个很棒的答案。我测试了它,它运行得很好。有两件事我想改进。

  1. I didn't like having to already have <iframe id="ifmcontentstoprint" style="height: 0px; width: 0px; position: absolute"></iframe>already in the dom tree.
  2. I wanted to create a way to make it reusable.
  1. 我不喜欢必须<iframe id="ifmcontentstoprint" style="height: 0px; width: 0px; position: absolute"></iframe>已经在 dom 树中。
  2. 我想创建一种方法来使其可重用。

I hope this makes others happy and saves a few minutes of life. Now go take those extra minutes and do something nice for someone.

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

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()
}

EDIT 2019-7-23: After using this more, this does have the downside that it doesn't perfectly render react components. This worked for me when the styling was inline but not when handled by styled-components or some other situations. If I come up with a foolproof method I will update.

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

回答by M Dutt

The solution provided by Emil Ingerslev is working fine, but CSS is not applied to the output. Here I found a good solution given by Andrewlimaza. It prints the contents of a given div, as it uses the window object's print method, the CSS is not lost. And there is no need for an extra iframe also.

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

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

Update 1: There is unusual behavior, in chrome/firefox/opera/edge, the print or other buttons stopped working after the execution of this code.

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

Update 2: The solution given is there on the above linkin comments:

更新 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>

回答by eox.dev

Just sharing what worked in my case as someone else might find it useful. I have a modal and just wanted to print the body of the modal which could be several pages on paper.

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

Other solutions I tried just printed one page and only what was on screen. Emil's accepted solution worked for me:

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

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

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

This is what the component ended up looking like. It prints everything in the body of the modal.

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

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>
        )
    }
}

Note: However, I am having difficulty getting styles to be reflected in the iframe.

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