【问题标题】:React - styling in component with javascript fileReact - 使用 javascript 文件在组件中设置样式
【发布时间】:2020-02-27 10:39:06
【问题描述】:

我正在尝试修改这个 Codepen loading animation,它具有三元组 [标记、样式和逻辑],并将其用作可导出的反应组件。

为此,我尝试从css 文件导入css,从js 文件导出javascript 函数,并在我的组件内的<div> 中呈现html


这是我目前的代码:

Loading.jsx

import React, { Component } from 'react';
import './css/clock.css';
import * from './js/clock.js';

class Loading extends Component {
    render() {
        return (
            <div>
              <div className="container">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
              <title>clock coffee cup</title>
              <defs>
                <clipPath id="cupMask">
                    <path className="cupMask" d="M215.65,214.41c0,19.85,37.76,35.94,84.35,35.94s84.35-16.09,84.35-35.94H506V399H145V214.41h70.65Z" fill="#ff0d0d"/>
                </clipPath>
                <clipPath id="handleMask">
                    <path className="handleMask" fill="#4BFF00" d="M475,305c-23.7-2.4-104.6,3.9-104.6,3.9s12.1-11.9,13.9-46.2c0,0,2.3-39.9,0-48.3
                    c9.9,0,90.6,0,90.6,0V305z"/>
                </clipPath>    
              </defs>
              <g className="cupGroup">

                  <ellipse className="ripple" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="6"/>
                  <ellipse className="ripple" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="6"/>    
                <g clipPath="url(#cupMask)">
                      <path id="base" d="M216,214v48.7
                c0,46.4,37.8,84.4,84.2,84.4h-0.3c46.4,0,84.1-38,84.1-84.4V214" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
                </g>
                <g clipPath="url(#handleMask)">
                  <path opacity="1" id="handle" d="M384.5,228.7c15.9,0,27.8,13.6,27.8,31.5s-14.9,30.5-30.8,30.5" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
                </g>    
                <ellipse id="rim" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
              </g>
            <g className="clockGroup" opacity="1">
            <line id="bighand" fill="none" strokeWidth="14" strokeLinecap="round" strokeMiterlimit="10" x1="300" y1="263" x2="300" y2="189"/>
            <line id="littlehand" fill="none" strokeWidth="14" strokeLinecap="round" strokeMiterlimit="10" x1="300" y1="263" x2="300" y2="221"/>                 
              </g>
              <line id="table" x1="235" y1="376" x2="365" y2="376" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>                 
            </svg>


            </div>
            </div>
        );
    }
}
export default Loading; 

clock.css

body {
  background-color:#FFF9ED;
  overflow: hidden;
}

body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}
.container{
  position:absolute;
  width:600px;

}

svg{
  visibility:hidden;

}

line, ellipse, path{
  stroke:#574227;
}

clock.js

var xmlns = "http://www.w3.org/2000/svg",
  xlinkns = "http://www.w3.org/1999/xlink",
  select = function(s) {
    return document.querySelector(s);
  },
  selectAll = function(s) {
    return document.querySelectorAll(s);
  },
  container = select('.container'),
  cupGroup = select('.cupGroup'),
    littlehand = select('#littlehand'),
    bighand = select('#bighand'),
    cupColour = '#574227',
  clockColour = '#70A0A0',
    rippleColour = '#AD834E'

//center the container cos it's pretty an' that
TweenMax.set(container, {
  position: 'absolute',
  top: '50%',
  left: '50%',
  xPercent: -50,
  yPercent: -50
})
TweenMax.set('svg', {
  visibility: 'visible'
})
TweenMax.set([littlehand, bighand],{
  transformOrigin:'50% 100%'
})

export function makeAnimation(){
  var tl = new TimelineMax({delay:2, onComplete:makeAnimation});
  tl.to('#rim', 1, {
    attr:{
      ry:84.35
    },
    stroke:clockColour
  })
  .to('#base', 1, {
    y:-47.5,
    stroke:clockColour
  },'-=1')
  .to('#table', 0.8, {
    drawSVG:'40% 60%',
    alpha:0
  },'-=1')
  .to('#handle', 0.3, {
    x:-50,
    stroke:clockColour,
    ease:Power1.easeIn
  },'-=1')
  .to(cupGroup, 1, {
    y:36,
    ease:Back.easeOut
  },'-=1')
  .fromTo([bighand,littlehand], 1, {
    drawSVG:'-1% -1%',
    y:20
  },
    {
    y:0,
    stroke:clockColour,
    drawSVG:'0% 70%',
    ease:Back.easeOut

  },'-=0.6')
  /* .to([littlehand, bighand], 0.1, {
        rotation:0               
    }) */
  .addCallback(setClock,'+=0.4')

  .to([bighand], 2, {
    rotation:0,
    ease:Power1.easeInOut,
    delay:5
  })
    .to([littlehand], 2, {
    rotation:-360,
    ease:Power1.easeInOut
  },'-=2')
  .to([bighand,littlehand], 0.6, {
    drawSVG:'-1% -1%',
    y:-40,
    stroke:cupColour,
    ease:Back.easeIn
  })
  .to('#rim', 1, {
    attr:{
      ry:35.94
    },
    stroke:cupColour,
  },'-=0.6')
  .to('#base', 1, {
    y:0,
    stroke:cupColour,
  },'-=1')

  .to(cupGroup, 1, {
    y:0,
    ease:Back.easeInOut
  },'-=1')
  .to('#handle', 0.6, {
    x:0,
    stroke:cupColour,
  },'-=0.6')
  .staggerFromTo('.ripple', 3, {
    attr:{
      rx:0,
      ry:0
    },
    stroke:'#f7f7f7'
  },{
    attr:{
      rx:84,
      ry:36 
    },
    alpha:1,
    stroke:rippleColour

  },0.4,'-=0.6')
  .to('#table', 0.5, {
    drawSVG:'0% 100%',
    alpha:1
  },'-=3.4')


  tl.timeScale(1.8)  

}

//ScrubGSAPTimeline(tl);
//tl.progress(1)

export function setClock(){

    TweenMax.set([littlehand, bighand], {
      rotation:0               
  })
    //new date reference every minute
    var myDate = new Date();

    //hours minutes and seconds from Date object
    var hours = myDate.getHours();
    var minutes = myDate.getMinutes();
    var seconds = myDate.getSeconds();

    //minute position calculation
    var minuteValue = minutes*6;
    TweenMax.to(bighand,1.2, {
      shortRotation:minuteValue,
      ease:Back.easeOut.config(0.6)
    });

    //hour position calculation
    var hourValue = hours*30 +(minutes/2);         
    TweenMax.to(littlehand,1.2, {
      shortRotation:hourValue
    });



}

makeAnimation();

index.html,我链接了codepen页面所需的javascript设置,如下所示:


index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <meta name="theme-color" content="#000000" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link href="//cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"rel="stylesheet">
    <link href="//cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js">
    <link href="//s3-us-west-2.amazonaws.com/s.cdpn.io/35984/ScrubGSAPTimeline.js">
    <link href="//s3-us-west-2.amazonaws.com/s.cdpn.io/16327/DrawSVGPlugin.js?r=12">
    <link type="text/css" href="%PUBLIC_URL%/bootstrap.min.css" />
<!--     <script src="https://unpkg.com/react-media-player/dist/react-media-player.js"></script> -->

    <title>App</title>
  </head>

  <body>
<!--     <style>
    body {background-color: #C86428;
          background-image: url("bg.png");
          background-position: 0 5;
          opacity: 1.0;
          height: 120vh;}
    </style> -->
    <style>
      @import url(https://fonts.googleapis.com/css?family=Josefin+Sans:100,400);
      html, body {background:rgb(223,189,150);
                  font-family: 'Josefin Sans', sans-serif;
                  margin: 0px;
                  padding: 0px;
                  line-height:2.5em;}
      h1 {
          margin:0;
      }
    </style>

    <div id="root">
    </div>

  </body>
</html>

在我的 App.jsx 中导入组件:

import Page from './components/Page';

并像这样渲染它:

<Route exact path='/page' render={() => (
   <Page
   />
)} />

最后在 Page.jsx 中导入 Loading.jsx,如下所示:

import Loading from './Loading.jsx';

这是我的项目结构:

public/
      index.html
      js/
src/
   App.jsx
   index.js
   components/
             Page.jsx
             Loading.jsx
             css/
                clock.css
             js/
               clock.js

但没有渲染任何内容。我究竟做错了什么?

【问题讨论】:

  • 你能发布你的 App.jsx 文件吗?
  • 它很大。它的任何特定部分?
  • 如果 App 是你的入口文件(在 index.html 中使用,通常为 id="root")你需要在某处导入 。那部分会有所帮助
  • 你在哪里导入你的加载组件?
  • 请参考编辑。希望对您有帮助。

标签: javascript html css reactjs


【解决方案1】:

您必须进行一些修改。

您正在使用链接标签来加载 javascript。你需要改成script标签。

<link href="//cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js">

clock.js 依赖于渲染的 dom 元素。在渲染 DOM 之前,您不应该让脚本运行。使用componentDidMount生命周期方法加载脚本。

如果它是一个自执行脚本,您可以使用动态导入。在这种情况下,您可能需要为所有全局变量添加前缀window.。例如window.TweenMaxwindow.Power1window.Back

componentDidMount(){
        import("./js/clock.js");
 }

您可以更改脚本以导出默认函数并在componentDidMount中运行该函数

export default () => {
  //All the clock.js code
makeAnimation();
}

并用作

import makeAnimation from "./js/clock";

class Loading extends Component {

    componentDidMount(){
        makeAnimation();
    }

Demo using this approach

纯 DOM 操作(如果是外部脚本)。

componentDidMount(){
             fetch("url").then(res => res.text()).then(text => {
    const script = document.createElement("script");
    script.innerHTML = text;
    document.head.appendChild(script);
}

您可以运行下面的堆栈 sn-p 来查看动画效果。

class Loading extends React.Component {

    componentDidMount(){
             fetch("https://codepen.io/nithinthampi/pen/JjjOQVv.js").then(res => res.text()).then(text => {
    const script = document.createElement("script");
    script.innerHTML = text;
    document.head.appendChild(script);
}
);
    }
    
    render() {
        return (
            <div>
              <div className="container">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
              <title>clock coffee cup</title>
              <defs>
                <clipPath id="cupMask">
                    <path className="cupMask" d="M215.65,214.41c0,19.85,37.76,35.94,84.35,35.94s84.35-16.09,84.35-35.94H506V399H145V214.41h70.65Z" fill="#ff0d0d"/>
                </clipPath>
                <clipPath id="handleMask">
                    <path className="handleMask" fill="#4BFF00" d="M475,305c-23.7-2.4-104.6,3.9-104.6,3.9s12.1-11.9,13.9-46.2c0,0,2.3-39.9,0-48.3
                    c9.9,0,90.6,0,90.6,0V305z"/>
                </clipPath>    
              </defs>
              <g className="cupGroup">

                  <ellipse className="ripple" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="6"/>
                  <ellipse className="ripple" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="6"/>    
                <g clipPath="url(#cupMask)">
                      <path id="base" d="M216,214v48.7
                c0,46.4,37.8,84.4,84.2,84.4h-0.3c46.4,0,84.1-38,84.1-84.4V214" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
                </g>
                <g clipPath="url(#handleMask)">
                  <path opacity="1" id="handle" d="M384.5,228.7c15.9,0,27.8,13.6,27.8,31.5s-14.9,30.5-30.8,30.5" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
                </g>    
                <ellipse id="rim" cx="300" cy="214.41" rx="84.35" ry="35.94" fill="rgba(0,0,0,0)" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>
              </g>
            <g className="clockGroup" opacity="1">
            <line id="bighand" fill="none" strokeWidth="14" strokeLinecap="round" strokeMiterlimit="10" x1="300" y1="263" x2="300" y2="189"/>
            <line id="littlehand" fill="none" strokeWidth="14" strokeLinecap="round" strokeMiterlimit="10" x1="300" y1="263" x2="300" y2="221"/>                 
              </g>
              <line id="table" x1="235" y1="376" x2="365" y2="376" fill="none" strokeLinecap="round" strokeMiterlimit="10" strokeWidth="14"/>                 
            </svg>


            </div>
            </div>
        );
    }
}

ReactDOM.render(<Loading />, document.getElementById("root"));
body {
  background-color:#FFF9ED;
  overflow: hidden;
}

body,
html {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}
.container{
  position:absolute;
  width:600px;

}

svg{
  visibility:hidden;

}

line, ellipse, path{
  stroke:#574227;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css"rel="stylesheet">
    <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js"></script>
    
    <div id="root"></div>

请注意,您使用的所有插件都不是开源的。

https://codepen.io/GreenSock/full/OPqpRJ/

【讨论】:

    【解决方案2】:

    这是因为脚本 clock.jsLoading 组件挂载到 dom 之前执行。 container = select('.container')cupGroup = select('.cupGroup') 将变为空。所以注意正在页面上呈现。

    您应该在生命周期componentDidMount 中执行clock.js 中的脚本。

    clock.js

    export funtion initClock() {
        // write the script in clock.js here
    }
    

    正在加载.jsx

    import {initClock} from '.js/clock.js'
    
    class Loading extends Component {
        render() {}
        componentDidMount() {
            initClock();      
        }
    }
    

    【讨论】:

      【解决方案3】:

      您可以将样式导入到如下页面:

      import clockCSS from 'styles/App.module.css';
      

      在页面中,您可以将 styleclass 指定为:

      className={clockCSS.container}
      

      在style.css文件中你要更新定义styleclasses的方式:

      :local(.container){
          position:absolute;
          width:600px;
      }
      

      【讨论】:

        猜你喜欢
        • 2018-07-30
        • 2018-12-28
        • 2020-11-17
        • 2019-02-07
        • 2021-09-15
        • 2021-06-16
        • 1970-01-01
        • 2020-08-10
        • 1970-01-01
        相关资源
        最近更新 更多