【问题标题】:Styled components are not rendering in React Iframe?样式化的组件不在 React Iframe 中呈现?
【发布时间】:2021-06-07 22:10:43
【问题描述】:
  1. 列表项

我创建了一个 React Iframe(使用“react-frame-component”)和一些样式组件。当我尝试在 React Iframe 中渲染样式化组件时,样式化组件继承了父级 (App.css) 样式,并失去了其独特的样式。是否可以维护样式化的组件?

这是我的代码:

内容.js

import React from 'react';
import ReactDOM from 'react-dom';
import Frame, { FrameContextConsumer } from 'react-frame-component';
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 './components/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;

风格:

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

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

组件:

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;

尝试为 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-component';
import { StyleSheetManager } from 'styled-components';
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";
   }
}

【问题讨论】:

    标签: javascript reactjs react-native iframe styled-components


    【解决方案1】:

    我遇到了同样的问题。我最终创建了一个名为 StyledFrame 的辅助组件。

    发生的情况是您的样式组件 css 正在父框架中呈现。您需要拦截这些样式,并将它们呈现在您的 iframe 中。这就是 StyleSheetManager 的用途。

    您可以像使用 Frame 组件一样使用 StyledFrame。

    import React, { useContext } from 'react';
    import Frame, { FrameContext } from 'react-frame-component';
    import { StyleSheetManager } from 'styled-components';
    
    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>;
    };
    
    

    【讨论】:

    • 谢谢。在您的代码中,当您声明 const {style, children, ...otherProps } 时,这究竟是什么?这是否意味着我需要使用我为每个组件创建的 styled.div,并且必须在我的 content.js 文件中声明它?
    • @LemonSquareCakes 那只是道具解构。如果你注意到了,我将 style 属性传播到 style 中,并在 InjectingFrameStyles 之后渲染子元素。其余的作为 otherProps 散布在 Frame 上。您可以更改初始内容和样式以满足您的需求。
    • 像魅力一样工作!
    猜你喜欢
    • 2021-11-02
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 2023-02-02
    • 2020-09-26
    • 2017-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多