简体   繁体   English

react - 确保在 iframe 渲染之前加载 css

[英]react - ensure css loaded before iframe renders

Dealing with a flash of unstyled content issue.处理一闪而过的无样式内容问题。 I've got a chat widget that is injected onto users' pages.我有一个注入用户页面的聊天小部件。 So that I don't clash with existing styles.这样我就不会与现有的样式发生冲突。 I'm rendering in an iframe using react-frame-component .我正在使用react-frame-component在 iframe 中渲染。 This works pretty nicely, but one problem I have is with the CSS.这很好用,但我遇到的一个问题是 CSS。

react-frame-component accepts a prop head that you can use to pass a link to a stylesheet. react-frame-component接受一个 prop head ,您可以使用它来将链接传递到样式表。 Using MiniCSSExtractPlugin, I am able to get my css into a separate file that I can then link to:使用 MiniCSSExtractPlugin,我可以将我的 css 放入一个单独的文件中,然后我可以链接到:

render(props, state) {
  return (
    <Frame 
      head={<link rel="stylesheet" type="text/css" href="style.css" />}
      scrolling="no"
    >
      <ChatWidget />
    </Frame>
  );
}

With this, I get the dreaded flash of unstyled content.有了这个,我得到了可怕的无样式内容的闪光。 I think it's because everything including <ChatWidget> renders before the css can be fully downloaded.我认为这是因为包括<ChatWidget>在内的所有内容都在 css 可以完全下载之前呈现。

Is there a way I can ensure the CSS is downloaded before everything renders?有没有办法可以确保在一切呈现之前下载 CSS?

Also, not sure if it matters, but I'm using Preact.另外,不确定它是否重要,但我正在使用 Preact。

I ended up writing my own iframe component, using some tips from react-frame-component but writing it in a way I could be sure I had control over how it rendered.我最终编写了我自己的 iframe 组件,使用了react-frame-component一些技巧,但以一种我可以确定我可以控制它的呈现方式的方式编写它。 Here's what my iframe component looks like (note this uses Preact, which has some minor differences from React - it would be very easy to replicate this in React):这是我的 iframe 组件的样子(注意这里使用的是 Preact,它与 React 有一些细微的差别——在 React 中复制它会很容易):

import {h, Component, createRef} from 'preact';
import {createPortal} from 'preact/compat';
import {cssLink} from '../utilities';

export default class Frame extends Component {
  iframeNode = createRef();
  iframeTest = document.createElement('iframe');

  static initialContent() {
    return `<!DOCTYPE html><head><link rel="stylesheet" type="text/css" href="${cssLink}"></head><body></body></html>`;
  }

  componentDidMount() {
    this.iframeNode.addEventListener('load', this.handleLoad);
  }

  handleLoad = () => {
    this.iframeRoot = this.iframeNode.contentDocument.body;
    this.forceUpdate();
  };

  sourceProp() {
    const canUseSrcDoc = 'srcdoc' in this.iframeTest;

    if (canUseSrcDoc) {
      return {
        srcdoc: Frame.initialContent(),
      };
    }

    // inserting Frame.initialContent() as the src is a hack for older browsers
    // to allow inserting our stylesheet before the children render, preventing
    // flashes of unstyled content
    return {
      src: `javascript: '${Frame.initialContent()}'`,
    };
  }

  render(props) {
    const {children, ...rest} = props;

    return (
      <iframe
        {...rest}
        {...this.sourceProp()}
        ref={ref => (this.iframeNode = ref)}
      >
        {this.iframeRoot && createPortal(children, this.iframeRoot)}
      </iframe>
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM