【发布时间】:2015-05-09 02:45:01
【问题描述】:
如何在单击按钮时只打印一个组件。
我知道这个解决方案:
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
$('.print_frame').remove();
但是 React 不想使用框架。
有什么解决办法吗?谢谢。
【问题讨论】:
标签: javascript reactjs
如何在单击按钮时只打印一个组件。
我知道这个解决方案:
window.frames["print_frame"].window.focus();
window.frames["print_frame"].window.print();
$('.print_frame').remove();
但是 React 不想使用框架。
有什么解决办法吗?谢谢。
【问题讨论】:
标签: javascript reactjs
客户端上有两种解决方案。一个是像你发布的框架。您可以使用 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'));
值得注意的是,您可以在模板中创建新的或利用现有的子组件,并且所有内容都应该可以很好地打印。
【讨论】:
document.getElementById('root')怎么办?
document.getElementById(),因为它被认为是一个单页应用程序?如果你需要像ReactDOM.render(<MyTemplate/>, document.getElementById('print-mount'), document.getElementById('root')) 这样的东西怎么办?
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: 上面的link在cmets中有给出的解决方案:
.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 的出色答案。我对其进行了测试,并且效果很好。有两件事我想改进。
<iframe id="ifmcontentstoprint" style="height: 0px; width: 0px; position: absolute"></iframe> 已经在 dom 树中。我希望这能让其他人开心并挽救几分钟的生命。现在去多花点时间,为别人做点好事吧。
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 />
【讨论】: