在点击响应中打开新窗口中的组件

时间:2017-11-30 13:20:17

标签: javascript reactjs

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

-Wall

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

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

5 个答案:

答案 0 :(得分:6)

您可以使用ReactDOM.createPortal在新窗口中呈现组件David Gilbertsonpost中解释:

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();
  }
}

答案 1 :(得分:4)

此答案基于David Gilbertson's post。它已被修改以在Edge中工作。为了使它在Edge divstyle中起作用,元素必须为created with the window into which they will be rendered

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);  
  }
}

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

答案 2 :(得分:0)

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

至于大小,你在open的第三个参数中将它作为一个字符串提供,你实际上是正确的:

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

但请注意,由于各种原因,浏览器可能不会考虑您的宽度和高度请求。出于这个原因,如果它打开的空间比你想要的大,那么也可以使用适当的CSS来获得合适大小的空间。

答案 3 :(得分:0)

推荐的答案很棒!

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

const WindowScope = (props) => {
  const containerEl = useRef(document.createElement("div"));
  const externalWindow = useRef(null);

  useEffect(() => {
    externalWindow.current = window.open(
      "",
      "",
      "width=600,height=400,left=200,top=200"
    );
    const currentWindow = externalWindow.current;
    if (currentWindow) {
      currentWindow.document.body.appendChild(containerEl.current);
      return () => currentWindow.close();
    }
  }, []);

  return createPortal(props.children, containerEl.current);
};

答案 4 :(得分:0)

添加到当前答案 - 将样式从原始窗口复制到弹出窗口,您可以:

function copyStyles(src, dest) {
    Array.from(src.styleSheets).forEach(styleSheet => {
        dest.head.appendChild(styleSheet.ownerNode.cloneNode(true))
    })
    Array.from(src.fonts).forEach(font => dest.fonts.add(font))
}

然后添加

copyStyles(window.document, popupWindow.document);

在调用 window.open 之后,并且一旦 ref 被初始化