单击反应在新窗口中打开组件

Van*_*ana 11 javascript reactjs

我有一个显示数据的组件。单击父组件的按钮/链接后,我必须在新窗口中打开该组件。

export default class Parent extends Component {
    construtor(props) {
        super(props);
    }

    viewData = () => {
        window.open('childcomponent.js','Data','height=250,width=250');
    }

    render() {
        return (
            <div> <a onclick={this.viewData}>View Data</a></div>
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何调用另一个组件并在指定的新窗口中显示它。

实际上,我需要向该子组件发送一个道具,它将通过该道具从数据库中获取我的数据并进行渲染。

CD.*_*D.. 12

您可以使用David Gilbertson在他的帖子中解释的在ReactDOM.createPortal新窗口中渲染组件:

class MyWindowPortal extends React.PureComponent {
  constructor(props) {
    super(props);
    // STEP 1: create a container <div>
    this.containerEl = document.createElement('div');
    this.externalWindow = null;
  }

  render() {
    // STEP 2: append props.children to the container <div> that isn't mounted anywhere yet
    return ReactDOM.createPortal(this.props.children, this.containerEl);
  }

  componentDidMount() {
    // STEP 3: open a new browser window and store a reference to it
    this.externalWindow = window.open('', '', 'width=600,height=400,left=200,top=200');

    // STEP 4: append the container <div> (that has props.children appended to it) to the body of the new window
    this.externalWindow.document.body.appendChild(this.containerEl);
  }

  componentWillUnmount() {
    // STEP 5: This will fire when this.state.showWindowPortal in the parent component becomes false
    // So we tidy up by closing the window
    this.externalWindow.close();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 包装好的解决方案很好地放在了npm模块中:https://www.npmjs.com/package/react-new-window (4认同)

Rya*_*lor 8

该答案基于David Gilbertson的帖子。它已被修改以在Edge中工作。为了使这项工作在边缘divstyle元件必须与为他们将要呈现的窗口中创建

class MyWindowPortal extends React.PureComponent {
  constructor(props) {
    super(props);
    this.containerEl = null;
    this.externalWindow = null;
  }

  componentDidMount() {
    // STEP 1: Create a new window, a div, and append it to the window. The div 
    // *MUST** be created by the window it is to be appended to (Edge only)
    this.externalWindow = window.open('', '', 'width=600,height=400,left=200,top=200');
    this.containerEl = this.externalWindow.document.createElement('div');
    this.externalWindow.document.body.appendChild(this.containerEl);
  }

  componentWillUnmount() {
    // STEP 2: This will fire when this.state.showWindowPortal in the parent component
    // becomes false so we tidy up by just closing the window
    this.externalWindow.close();
  }

  render() {
    // STEP 3: The first render occurs before componentDidMount (where we open the
    // new window) so container may be null, in this case render nothing.
    if (!this.containerEl) {
      return null;
    } 

    // STEP 4: Append props.children to the container <div> in the new window
    return ReactDOM.createPortal(this.props.children, this.containerEl);  
  }
}
Run Code Online (Sandbox Code Playgroud)

完整的修改源可以在这里找到https://codepen.io/iamrewt/pen/WYbPWN

  • 我在窗口安装后第二次渲染时遇到了麻烦。除了当 this.containerEl 为空时,没有任何东西告诉它重新渲染。为了解决这个问题,我在 componentDidMount 的末尾添加了一个 setState({mopunted:true})。 (3认同)
  • 我可以使用它在弹出窗口中加载反应组件。但风格并没有被继承。弹出窗口中加载的组件不包含应用程序中定义的样式。有没有办法将样式传递到弹出窗口? (2认同)

rob*_*don 7

赞成的答案效果很好!

只是在这里留下一个功能组件版本,以防人们将来搜索它。

const RenderInWindow = (props) => {
  const [container, setContainer] = useState(null);
  const newWindow = useRef(null);

  useEffect(() => {
    // Create container element on client-side
    setContainer(document.createElement("div"));
  }, []);

  useEffect(() => {
    // When container is ready
    if (container) {
      // Create window
      newWindow.current = window.open(
        "",
        "",
        "width=600,height=400,left=200,top=200"
      );
      // Append container
      newWindow.current.document.body.appendChild(container);

      // Save reference to window for cleanup
      const curWindow = newWindow.current;

      // Return cleanup function
      return () => curWindow.close();
    }
  }, [container]);

  return container && createPortal(props.children, container);
};
Run Code Online (Sandbox Code Playgroud)

  • @rob-gordon知道为什么[这个](/sf/answers/4598959991/)在我的create-react-app生产版本中不起作用吗? (2认同)

sam*_*ime 5

您不会直接打开该组件。您将需要一个新的页面/视图来显示该组件。当您打开该窗口时,您将其指向适当的 URL。

至于大小,您可以在 open 的第三个参数中将其作为字符串提供,您实际上已经正确了:

window.open('http://example.com/child-path','Data','height=250,width=250');
Run Code Online (Sandbox Code Playgroud)

但请注意,浏览器可能出于各种原因不尊重您的宽度和高度请求。出于这个原因,最好还应用适当的 CSS 来获得正确大小的空间,以防它打开时比您想要的大。