javascript 样式组件动态CSS不会在新窗口中生成

kq4fsx7k  于 2023-04-04  发布在  Java
关注(0)|答案(3)|浏览(161)

我使用react-new-window打开一个弹出窗口,这个弹出窗口包括一些动态的组件(一个切换,一个下拉菜单,等等),样式是styled-components
一切都显示正常,直到我尝试与其中一个动态组件交互,它改变了状态(比如我将开关从off切换到on)。然后,结果是新组件状态的CSS类,通常生成并附加到<head>,实际上附加到父窗口的<head>,而不是弹出窗口。所以我的组件似乎失去了样式。
我在父窗口中也有同样的一堆组件。所以如果我在打开弹出窗口之前与它们交互,样式会像往常一样附加到<head>,然后复制到弹出窗口,看起来都很好。
所以我想到了两种可能的解决方法:
1.我可以告诉styled-component以某种方式与新窗口对话,而不是父窗口。
1.作为一种变通方法,我可以通过编程方式预先生成所有样式(样式并不多)。
问题是我不知道如何做这两件事。任何想法欢迎!

9bfwbjaz

9bfwbjaz1#

如果有人需要,这里有一个功能组件的工作示例

const Parent = () => {
  const [showPopout, setShowPopout] = useState(false)
  const [newWindowNode, setNewWindowNode] = useState(null)

  const nwRef = useCallback(node => setNewWindowNode(node), [])

  return showPopout 
    ? (
      <StyleSheetManager target={newWindowNode}>
        <NewWindow
          title="Title"
          features={{width: '960px', height: '600px'}}
          onUnload={() => setShowPopout(false)}
        >
          <div ref={nwRef}>
            <Popout isPopout={true}>
              ... popup stuff
            </Popout>
          </div>
        </NewWindow>
      </StyleSheetManager>
    ) : null
}
kqqjbcuj

kqqjbcuj2#

选项1解决方案实际上可以通过styled-component API实现:

import React from 'react';
import styled, {StyleSheetManager} from 'styled-components';
import NewWindow from 'react-new-window';

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      showPopout: false,
    };
    this.nwRef = React.createRef();
  }

  render () {
    ... some stuff
    this.state.showPopout && (
    <StyleSheetManager target={this.nwRef.current}>
      <NewWindow
        title="Title"
        features={{width: '960px', height: '600px'}}
        onUnload={() => this.setState({showPopout: false})}
      >
        <div ref={this.nwRef}>
          <Popout isPopout={true}>
            ... popup stuff
          </Popout>
        </div>
      </NewWindow>
    </StyleSheetManager>
  )}
}
idfiyjo8

idfiyjo83#

使用StyleSheetManager给予我的性能真的很差,也许样式表在每次重新渲染时都被重新创建。我更喜欢简单地复制样式表,就像www.example.com中建议https://github.com/JakeGinnivan/react-popout/issues/15#issuecomment-527429574。

import React, { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

// src: https://stackoverflow.com/questions/47574490/open-a-component-in-new-window-on-a-click-in-react
// you may also check: https://github.com/rmariuzzo/react-new-window/blob/main/src/NewWindow.js
// for stylesheet copy see: https://github.com/JakeGinnivan/react-popout/issues/15
export const RenderInWindow = (props: React.PropsWithChildren<
  {
    winName?: string;
  }
>) => {
  const [container, setContainer] = useState<HTMLDivElement|null>(null);
  const newWindow = useRef<Window|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(
        '',
        props.winName ?? '',
        "width=600,height=400,left=200,top=200"
      );

      if (!newWindow.current) {
        throw new Error('Failed to create window.');
      }

      // Append container
      newWindow.current.document.body.appendChild(container);

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

      copyStyles(document, newWindow.current!.document)

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

  return container && createPortal(props.children, container);
};

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

相关问题