Problem description

This is a React one-page project.

A requirement is a part of a page that needs to be printed.

It was written by someone else before, so you take it out, print it with document.innerhtml =, call the window.print method, and refresh the page with location.reload.

However, this method is abandoned because the page needs to be refreshed after the printing operation, which is bad for user experience.

<div id='preview'>Print the content</div>
Copy the code
document.body.innerHTML = document.getElementById('preview').innerHTML;
window.print();
location.reload();
Copy the code

Note:

Why not assign document.body to a variable and then reassign to document.body after printing?

This is because events declared on the React component end up bound to the Document DOM node. So if you assign document.body to a variable and then to document.body, there is no React event, and all subsequent page operations will be invalid.

How to solve

My solution is to create a new browser window and copy the content and styles to the new window for printing.

// Create a new browser window
const printViewWin = window.open(' '.'printView');
// Get print content
const str = this.createPrintHtml();
// Write the contents to the document via document.write
printViewWin.document.write(str);
// Closes data writing to the current document
printViewWin.document.close();

/* * There are production and development environments because of the webpack used * * in the development environment, all styles will be displayed as 
function createPrintHtml(){
  let str
  if (process.env.NODE_ENV === '"development"') {
    
    str = "
      
      " + 
      '' + 
      '<style>' +
      Array.from(window.document.querySelectorAll('style')).map(n= > n.innerText).join(' ') +
      '</style></head><body>' +
      window.document.getElementById('preview').innerHTML +
      '</body></html>';
  } else {
    
      
    str = "
      
      " + 
      '' +
      window.document.head.innerHTML.match(/href="(.*?) "/gi).filter(_= > _.endsWith('css"')).map(n= > n.slice(6)).map(n= > n.slice(0.- 1)).map(_= > `<link rel="stylesheet" type="text/css" href="${location.origin + _}" >`).join(' ') +
      '</head><body>' +
      window.document.getElementById('preview').innerHTML +
      '</body></html>';
  }
  return str
}
Copy the code

summary

Why not use ref to get print inside?

Yes. But get the DOM node directly. Because in this requirement, all you need to do is get the printed content, and nothing else needs to be done to the component.

Document.write can parse the written characters as HTML, and then manually close the document stream.

How to use Document. write?

In this scenario, document.write can be used. However, you can also inject styles and content into a document in a new window using methods such as appendChild.