最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Styled components are not rendering in React Iframe? - Stack Overflow

programmeradmin0浏览0评论
  1. List item

I've created a React Iframe (using 'react-frame-ponent'), and some styled ponents. When I try to render the styled ponents inside the React Iframe, the styled ponents inherits the Parent's (App.css) style, and loses its unique style. Is it possible to maintain the styled ponent?

Here is my code:

Content.js

import React from 'react';
import ReactDOM from 'react-dom';
import Frame, { FrameContextConsumer } from 'react-frame-ponent';
import App from "./App";
class Main extends React.Component {
    render() {
        return (
            <Frame head={[<link type="text/css" rel="stylesheet" href={chrome.runtime.getURL("/static/css/content.css")} ></link>]}>
               <FrameContextConsumer>
               {
                  ({document, window}) => {
                    return <App document={document} window={window} isExt={true}/>
                  }
                }
                </FrameContextConsumer>
            </Frame>

        )
    }
}
  1. List item

I've created a React Iframe (using 'react-frame-ponent'), and some styled ponents. When I try to render the styled ponents inside the React Iframe, the styled ponents inherits the Parent's (App.css) style, and loses its unique style. Is it possible to maintain the styled ponent?

Here is my code:

Content.js

import React from 'react';
import ReactDOM from 'react-dom';
import Frame, { FrameContextConsumer } from 'react-frame-ponent';
import App from "./App";
class Main extends React.Component {
    render() {
        return (
            <Frame head={[<link type="text/css" rel="stylesheet" href={chrome.runtime.getURL("/static/css/content.css")} ></link>]}>
               <FrameContextConsumer>
               {
                  ({document, window}) => {
                    return <App document={document} window={window} isExt={true}/>
                  }
                }
                </FrameContextConsumer>
            </Frame>

        )
    }
}

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Card from './ponents/Card/index';



class App extends Component {
  render() {
    return (
      <>
      <div className="App">
          {this.props.isExt ?
            <img src={chrome.runtime.getURL("static/media/logo.svg")} className="App-logo" alt="logo" />
          :
            <img src={logo} className="App-logo" alt="logo" />
          }
          <Card />
      </div>


      </>
    );
  }
}

export default App;

Style:

import React from "react";
import styled, { css } from "styled-ponents";

export const CardWrapper = styled.div`
  overflow: hidden;
  padding: 0 0 32px;
  margin: 48px auto 0;
  width: 300px;
  font-family: Quicksand, arial, sans-serif;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.05), 0 0px 40px rgba(0, 0, 0, 0.08);
  border-radius: 5px;
`;

export const CardHeader = styled.header`
  padding-top: 32px;
  padding-bottom: 32px;
`;

export const CardHeading = styled.h1`
  font-size: 24px;
  font-weight: bold;
  text-align: center;
`;

export const CardBody = styled.div`
  padding-right: 32px;
  padding-left: 32px;
`;

export const CardFieldset = styled.fieldset`
  position: relative;
  padding: 0;
  margin: 0;
  border: 0;

  & + & {
    margin-top: 24px;
  }

  &:nth-last-of-type(2) {
    margin-top: 32px;
  }

  &:last-of-type {
    text-align: center;
  }
`;

export const CardInput = styled.input`
  padding: 7px 0;
  width: 100%;
  font-family: inherit;
  font-size: 14px;
  border-top: 0;
  border-right: 0;
  border-bottom: 1px solid #ddd;
  border-left: 0;
  transition: border-bottom-color 0.25s ease-in;

  &:focus {
    border-bottom-color: #e5195f;
    outline: 0;
  }
`;

export const CardIcon = styled.span`
  color: #666;
  cursor: pointer;
  opacity: .25;
  transition: opacity .25s ease-in;

  &:hover {
    opacity: .95;
  }

  ${props =>
    props.big &&
    css`
      font-size: 26px;
    `}

  ${props =>
    props.eye &&
    css`
      position: absolute;
      top: 8px;
      right: 0;
    `}

  ${props =>
    props.small &&
    css`
      font-size: 14px;
    `}
`;

export const CardOptionsNote = styled.small`
  padding-top: 8px;
  display: block;
  width: 100%;
  font-size: 12px;
  text-align: center;
  text-transform: uppercase;
`;

export const CardOptions = styled.ul`
  padding: 0;
  margin: 16px 0 8px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  width: 100%;
  list-style-type: none;
`;

export const CardOptionsItem = styled.li`
  &:nth-of-type(n + 2) {
    margin-left: 16px;
  }
`;

export const CardButton = styled.button`
  display: block;
  width: 100%;
  padding: 12px 0;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  color: #fff;
  background-color: #e5195f;
  border: 0;
  border-radius: 35px;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.08);
  cursor: pointer;
  transition: all 0.25s cubic-bezier(0.02, 0.01, 0.47, 1);

  &:hover {
    box-shadow: 0 15px 15px rgba(0, 0, 0, 0.16);
    transform: translate(0, -5px);
  }
`;

export const CardLink = styled.a`
  display: inline-block;
  font-size: 12px;
  text-decoration: none;
  color: #aaa;
  border-bottom: 1px solid #ddd;
  cursor: pointer;
  transition: color 0.25s ease-in;

  &:hover {
    color: #777;
  }
`;

Component:

import React from "react";

import {
  CardWrapper,
  CardHeader,
  CardHeading,
  CardBody,
  CardIcon,
  CardFieldset,
  CardInput,
  CardOptionsItem,
  CardOptions,
  CardOptionsNote,
  CardButton,
  CardLink
} from './Card';


const Card = () => {
    return (
    <>
      <CardWrapper>
        <CardHeader>
          <CardHeading>Sign in</CardHeading>
        </CardHeader>

        <CardBody>
          <CardFieldset>
            <CardInput placeholder="Username" type="text" required />
          </CardFieldset>

          <CardFieldset>
            <CardInput placeholder="E-mail" type="text" required />
          </CardFieldset>

          <CardFieldset>
            <CardInput placeholder="Password" type="password" required />
            <CardIcon className="fa fa-eye" eye small />
          </CardFieldset>

          <CardFieldset>
            <CardOptionsNote>Or sign up with</CardOptionsNote>

            <CardOptions>
              <CardOptionsItem>
                <CardIcon className="fab fa-google" big />
              </CardOptionsItem>

              <CardOptionsItem>
                <CardIcon className="fab fa-twitter" big />
              </CardOptionsItem>

              <CardOptionsItem>
                <CardIcon className="fab fa-facebook" big />
              </CardOptionsItem>
            </CardOptions>
          </CardFieldset>

          <CardFieldset>
            <CardButton type="button">Sign Up</CardButton>
          </CardFieldset>

          <CardFieldset>
            <CardLink>I already have an account</CardLink>
          </CardFieldset>
        </CardBody>
      </CardWrapper>
    </>
  );
};

export default Card;

Attempt at injecting stylesheet for CardWrapper:

/*global chrome*/
/* src/content.js */

import React from 'react';
import { useContext, FrameContext } from 'react';
import ReactDOM from 'react-dom';
import Frame, { FrameContextConsumer } from 'react-frame-ponent';
import { StyleSheetManager } from 'styled-ponents';
import App from "./App";


export const StyledFrame = (props) => {
  const {
  CardWrapper,
  CardHeader,
  CardHeading,
  CardBody,
  CardFieldset,
  CardInput,
  CardIcon,
  CardOptionsNote,
  CardOptions,
  CardOptionsItem,
  CardButton,
  CardLink,
  } = props;

    class Main extends React.Component {
      render() {
          return (
            <Frame head={[<link type="text/css" rel="stylesheet" href={chrome.runtime.getURL("/static/css/content.css")} ></link>]}>
                <InjectFrameStyles>
                    {props.CardWrapper}
                </InjectFrameStyles>
            </Frame>
          )
      }
    }
};

const InjectFrameStyles = (props) => {
  const { document } = useContext(FrameContext);
  return <StyleSheetManager target={document.head}>{props.CardWrapper}</StyleSheetManager>;
}

const app = document.createElement('div');
app.id = "my-extension-root";

document.body.appendChild(app);
ReactDOM.render(<Main />, app);

app.style.display = "none";

chrome.runtime.onMessage.addListener(
   function(request, sender, sendResponse) {
      if( request.message === "clicked_browser_action") {
        toggle();
      }
   }
);

function toggle(){
   if(app.style.display === "none"){
     app.style.display = "block";
   }else{
     app.style.display = "none";
   }
}

Share Improve this question edited Mar 12, 2021 at 17:53 LemonSquareCakes asked Mar 10, 2021 at 0:36 LemonSquareCakesLemonSquareCakes 311 silver badge4 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 11

I had the same problem. I ended up creating a helper ponent called StyledFrame.

What happens is that your styled-ponents css is being rendered in the parent frame. You need to intercept those styles, and render them inside your iframe instead. Thats what StyleSheetManager is for.

You can use StyledFrame just like you would the Frame ponent.

import React, { useContext } from 'react';
import Frame, { FrameContext } from 'react-frame-ponent';
import { StyleSheetManager } from 'styled-ponents';

export const StyledFrame = (props) => {
  const { style, children, ...otherProps } = props;

  return (
    <Frame
      initialContent={
        '<!DOCTYPE html><html><head></head><body><div class="frame-root"></div><div id="modal-root"></div></body></html>'
      }
      style={{ display: 'block', overflow: 'scroll', border: 0, ...style }}
      {...otherProps}
    >
      <InjectFrameStyles>{props.children}</InjectFrameStyles>
    </Frame>
  );
};

const InjectFrameStyles = (props) => {
  const { document } = useContext(FrameContext);
  return <StyleSheetManager target={document.head}>{props.children}</StyleSheetManager>;
};

发布评论

评论列表(0)

  1. 暂无评论