Как распечатать компонент React при нажатии кнопки?

Как я могу напечатать только один компонент одним нажатием кнопки.

Я знаю это решение:

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

Но React не хочет работать с фреймом.

Любые решения? Спасибо.

Ответ 1

На клиенте существует несколько решений. Один из них с кадрами, как вы опубликовали. Вы можете использовать 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.

Ответ 2

6/19/2017 Это работало идеально для меня.

import React, {Component} from 'react'


class PrintThisComponent extends Component {

  componentDidMount() {

    console.log('PrintThisComponent mounted!')

  }

  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

Ответ 3

Если вы хотите распечатать конкретные данные, к которым у вас уже есть доступ, будь то из Магазина, AJAX или из других источников, вы можете использовать мою библиотеку реагировать на печать.

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

Это значительно упрощает создание шаблонов печати (при условии, что у вас уже есть зависимость от реакции). Вам просто нужно соответствующим образом пометить ваш HTML.

Этот идентификатор должен быть добавлен выше в вашем фактическом дереве DOM, чтобы исключить все, кроме "монтирования печати" ниже.

<div id="react-no-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'));

Стоит отметить, что вы можете создавать новые или использовать существующие дочерние компоненты внутри вашего шаблона, и все должно хорошо отображаться для печати.

Ответ 4

Вам придется @media print {} распечатку с помощью @media print {} в CSS, но простой код:

export default class Component extends Component {

    print(){
        window.print();
    }


  render() {

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

  } 
}

Надеюсь, что это полезно!

Ответ 5

Я искал простой пакет, который выполнил бы ту же самую задачу и ничего не нашел, поэтому я создал https://github.com/gregnb/react-to-print p >

Вы можете использовать его так:

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

Ответ 6

Сначала хочу отдать должное @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: после использования этого больше, это имеет недостаток, что он не идеально отображает реагирующие компоненты. Это сработало для меня, когда стиль был встроенным, но не когда он обрабатывался компонентами styled или какими-то другими ситуациями. Если я придумаю надежный метод, я обновлю.

Ответ 7

Просто поделиться тем, что сработало в моем случае, как кто-то другой, может оказаться полезным. У меня есть модал, и я просто хотел напечатать его текст, который мог бы состоять из нескольких страниц на бумаге.

Другие решения, которые я пробовал, просто печатали одну страницу и только то, что было на экране. Эмиль принял решение, сработавшее для меня:

fooobar.com/info/986853/...

Вот как в итоге выглядел компонент. Он печатает все в теле модала.

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.