使用React Portal打开新窗口时IE窗口空白问题求助
Hey there, let's break down why your component shows a blank page in IE and fix it step by step:
1. Critical Parameter Mix-Up in copyStyles
Looking at your componentDidMount code, you're passing containerEl (a div element) as the first argument to copyStyles, but the function expects the source document (your main page's document object) here. This means your style-copying logic wasn't running at all—Chrome might have swallowed the error, but IE stops execution when it hits this issue.
2. IE Doesn't Support Array.from()
Array.from() is an ES6 feature that IE has zero support for. We need to replace it with the ES5-compatible Array.prototype.slice.call() to convert array-like objects (like styleSheets and cssRules) into proper arrays.
3. Handle Potential CSS Rule Access Errors
In IE, trying to access cssRules on certain style sheets (like cross-origin ones) can throw a security error. Wrapping that logic in a try-catch block will prevent the entire function from failing.
4. Ensure New Window DOM is Ready
IE can be finicky about when you interact with a newly opened window's DOM. Adding a check for win.document.body and retrying if needed ensures we're modifying a fully initialized DOM.
Modified Working Code
import React from 'react'; import ReactDOM from 'react-dom'; export default class NewWindow extends React.Component { constructor(props) { super(props); this.state = { win: null, containerEl: null }; } componentDidMount() { const win = window.open('', '', 'width=600,height=400'); // Wait for the new window's DOM to be ready (IE-friendly) const checkDomReady = () => { if (win.document.body) { const containerEl = win.document.createElement('div'); win.document.body.appendChild(containerEl); // Fix: Pass the correct source document (main page's document) this.copyStyles(document, win.document); this.setState({ win, containerEl }); } else { setTimeout(checkDomReady, 50); } }; checkDomReady(); } copyStyles = (sourceDoc, targetDoc) => { // Replace Array.from with ES5-compatible slice.call const styleSheets = Array.prototype.slice.call(sourceDoc.styleSheets); styleSheets.forEach(styleSheet => { if (styleSheet.cssRules) { const newStyleEl = sourceDoc.createElement('style'); try { // Access cssRules safely with try-catch const cssRules = Array.prototype.slice.call(styleSheet.cssRules); cssRules.forEach(cssRule => { newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText)); }); targetDoc.head.appendChild(newStyleEl); } catch (e) { // Skip style sheets we can't access (like cross-origin) console.warn('Could not access cssRules for style sheet:', styleSheet.href); } } else if (styleSheet.href) { const newLinkEl = sourceDoc.createElement('link'); newLinkEl.rel = 'stylesheet'; newLinkEl.href = styleSheet.href; targetDoc.head.appendChild(newLinkEl); } }); } componentWillUnmount() { if (this.state.win) { this.state.win.close(); } } render() { const { containerEl } = this.state; if (!containerEl) { return null; } return ReactDOM.createPortal(this.props.children, containerEl); } }
Additional Notes for IE Compatibility
- Polyfills: Make sure you're including polyfills for ES6 features like
PromiseandObject.assign(if your React version requires them). Tools likecore-jscan help cover these gaps. - React Version: Ensure you're using a React version that supports Portal (React 16+) and has IE compatibility patches applied.
- Test Edge Cases: Test with different stylesheet types (inline, external) to make sure all necessary styles are copied over to the new window.
内容的提问来源于stack exchange,提问作者Shalini98279

