How to print React component on click of a button?

前端 未结 8 2056
执念已碎
执念已碎 2020-12-03 01:42

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         


        
相关标签:
8条回答
  • 2020-12-03 01:51

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

    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
    
    0 讨论(0)
  • 2020-12-03 01:54

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

    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

    <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.

    <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.

    0 讨论(0)
  • 2020-12-03 01:56

    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.

    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.

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

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

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

    <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.

    0 讨论(0)
  • 2020-12-03 02:02

    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

    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.

    0 讨论(0)
  • 2020-12-03 02:14

    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.

    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.

    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.

    0 讨论(0)
  • 2020-12-03 02:16

    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

    You can use it like so:

     <ReactToPrint
       trigger={() => <a href="#">Print this out!</a>}
       content={() => this.componentRef}
     />
     <ComponentToPrint ref={el => (this.componentRef = el)} />
    
    0 讨论(0)
提交回复
热议问题