【问题标题】:How to make CSS animation not affecting other HTML in React?如何使 CSS 动画不影响 React 中的其他 HTML?
【发布时间】:2022-01-01 16:21:30
【问题描述】:

我正在使用 React 制作一个名为 Random Quote Machine 的项目。并尝试在 React 组件中的状态更新时进行一些动画转换。但我不希望动画过渡影响所有内容。

在进入问题之前,这是我的代码:

CSS 代码:

@import url('https://fonts.googleapis.com/css2?family=Bitter:ital,wght@0,200;0,400;0,600;0,700;1,400&display=swap');

// Font Variable
$main-fonts: 'Bitter', serif;

// Color variable
$default-color: #d1d1d1;
$white-color: #ffffff;
$black-color: #000000;

// Animation Fade-In transition
@mixin animation($time){ 
  animation: fadeIn $time;
  -webkit-animation: fadeIn $time;
  -moz-animation: fadeIn $time;
  -o-animation: fadeIn $time;
  -ms-animation: fadeIn $time;
}

// Start of evert keyframes //
@keyframes fadeIn {
  0% {opacity:0;}
  100% {opacity:1;}
}

@-moz-keyframes fadeIn {
  0% {opacity:0;}
  100% {opacity:1;}
}

@-webkit-keyframes fadeIn {
  0% {opacity:0;}
  100% {opacity:1;}
}

@-o-keyframes fadeIn {
  0% {opacity:0;}
  100% {opacity:1;}
}
// End of keyframes //

// Classes to add to React when state updated for it's element performed the animation
.animation-transition {
  @include animation(2.5s);
}

// HTML LAYOUT //
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  color: $white-color;
  font-family: $main-fonts;
  font-weight: 700;
  line-height: 1.6;
}
 
.wrapper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100vw;
  height: 100vh;
}

.quote-box {
    background: $white-color;
    display: table;
    width: 500px;
    padding: 2rem 3rem;
    border-radius: 5px;
    z-index: 1;
    
    .quote {
      color: $black-color;
      padding: 0rem 1.6rem;
      
      
      .quote-text {
        font-size: 1.3rem;
      }
      
      .quote-icon {
        width: 35px;
        margin-bottom: -8px;
        margin-right: 10px;
      }
  }
  
    .quote-author {
      color: $black-color;
      text-align: right;
      padding: 1.5rem 0rem;
      font-weight: 400;
    }
  
    .buttons {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-top: 0.45rem;
    
      & > * {
          background-color: $black-color;
          color: $white-color;
          height: 38px;
          border-radius: 3px;
          font-weight: 400;
          padding: 0.5rem 1rem;
          cursor: pointer;
      }
      
      .tweet-quote-button {
        text-decoration: none;
        font-size: 0.9rem;
      }
      
      .new-quote-button {
        font-size: 0.85rem;
      }
      
      .tweet-quote-button:hover, .new-quote-button:hover {
        opacity: 0.8;
      }
   }
}

.footer {
  text-align: center;
  font-weight: 600;
  font-size: 0.8rem;
  margin-top: 1rem;
  
  span a {
    color: $white-color;
    text-decoration: none;
  }
}

反应代码:

// START OF App Parent Component //
class App extends React.Component {
  constructor(props) {
    super(props); 
    this.state = {
      quote: "",
      author: "",
      color: "",
      fade: false
    }
    
    this.getData = this.getData.bind(this);
    this.handleClick = this.handleClick.bind(this);
    this.animationStart = this.animationStart.bind(this);
  }
  
  /* RANDOMLY GET VALUE FROM QUOTE OBJECT and color arrays to store as state value */
  getData() {
    const n = Math.floor(Math.random() * 21);
    const q = QUOTE[n]['quote'];
    const a = QUOTE[n]['author'];
    const c = colors[n];
    
    this.setState({
      quote: q,
      author: a,
      color: c
    });  
  }
  
  /* TRIGGERED WHEN USER CLICK BUTTON TO SET STATE TRUE OR FALSE OF TRANSITION ANIMATION */
  animationStart() {
    this.setState({
      fade: true
    })
    
    
    setTimeout(() => {
      console.log("false called");
      this.setState({
        fade: false
      })  
    }, 2400);
  }
  
  /* TRIGGER WHEN USER CLICK NEW QUOTE BUTTON, GET NEW VALUE FOR STATE TO RENDERED */
  handleClick() {
    this.getData();
    this.animationStart();
  }
  
  /* THIS WILL HANDLE STATE TO PASS TO CHILD IN VERY FIRST RENDER */
  componentDidMount() {
    this.getData();
    this.animationStart();
  }
  
  render() {
    return (
      <div>
        <QuoteBox quote={this.state.quote} author={this.state.author} color={this.state.color} fade={this.state.fade} handleClick={this.handleClick}/>
      </div>
    )
  }
}
// END OF PARENT COMPONENT //

// START OF QUOTE BOX CHILD COMPONENT //
class QuoteBox extends React.Component {
  constructor(props) {
    super(props)
  }
  
  render() {
    {/* GET QUOTE-LEFT ICON FROM CODEPEN ASSETS*/}
    const iconQuote = <svg class="quote-icon" viewBox="0 0 512 512" title="quote-left">
  <path d="M464 256h-80v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8c-88.4 0-160 71.6-160 160v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48zm-288 0H96v-64c0-35.3 28.7-64 64-64h8c13.3 0 24-10.7 24-24V56c0-13.3-10.7-24-24-24h-8C71.6 32 0 103.6 0 192v240c0 26.5 21.5 48 48 48h128c26.5 0 48-21.5 48-48V304c0-26.5-21.5-48-48-48z" />
</svg>
      
    {/* CHANGE THE BACKGROUND OF HTML BODY AFTER RENDER*/}
    {/*document.body.style.backgroundColor = this.props.color;
    
    if (this.props.fade) {
      document.body.classList.add('animation-transition');
    } else {
      document.body.classList.remove('animation-transition');
    }*/}
    
    return (
      <div style={{'backgroundColor': this.props.color}} className={`wrapper ${this.props.fade ? 'animation-transition' : ''}`}>
        {/* START OF QUOTE BOX WRAPPER */}
          <div id="quote-box" className="quote-box">
            {/* QUOTE TEXT, ALWAYS UPDATE FROM PROPS PASSED BY PARENT'S STATE */}
            <div className="quote">
              <span style={{'color': this.props.color, 'fill': this.props.color}} id="text" className={`quote-text ${this.props.fade ? 'animation-transition' : ''}`}>{iconQuote} {this.props.quote}</span>
            </div>
            
            {/* AUTHOR TEXT, ALWAYS UPDATE FROM PROPS PASSED BY PARENT'S STATE */}
            <div style={{'color': this.props.color}} id="author" className={`quote-author ${this.props.fade ? 'animation-transition' : ''}`}>
              <span>- {this.props.author}</span>
            </div>
            
            {/* BUTTON WRAPPER */}
            <div className="buttons">
              
              {/* TWITTER BUTTON, UPDATE BACKGROUND FROM PROPS */}
              <a style={{'backgroundColor': this.props.color}} id="tweet-quote" class="tweet-quote-button" href="twitter.com/intent/tweet" target="_blank">
                tweet <FontAwesomeIcon icon={['fab', 'twitter']} />
              </a>
              
              {/* NEW QUOTE BUTTON, UPDATE BACKGROUND FROM PROPS */}
              <button style={{'backgroundColor': this.props.color}} id="new-quote" className="new-quote-button" onClick={this.props.handleClick} onAnimationEnd={this.props.animationEnd}>new quote</button>
            </div>
          </div>
        {/* END OF QUOTE BOX WRAPPER */}
        
        {/* START OF FOOTER */}
        <div className="footer">
          <span>created by <a href="https://codepen.io/thekevinkun" target="_blank">Kevinkun</a></span>
        </div>
        {/* END OF FOOTER */}
      
      </div>
    )
  }
}
// END OF CHILD COMPONENT //

ReactDOM.render(<App />, document.getElementById('root'));

希望大家可以访问codepen以获得更好的理解:My Projects

项目说明:每当用户点击新报价按钮时,它会在显示新报价以及新的文本颜色和背景颜色之前进行淡入淡出转换。

问题是:正如您在我的 codepen 中看到的那样,我不希望包裹所有内容的 白框 跟随动画过渡。

这是我要实现的例子:freeCodeCamp Random Quote Machine

您可以看到,在 freeCodeCamp 示例中,白框没有进行转换。

我知道这听起来很简单,但我被困住了。我希望你们理解并写一个解决方案。谢谢。

【问题讨论】:

    标签: html css reactjs animation css-transitions


    【解决方案1】:

    不要将animation-transition 类添加到wrapper div。您所指的示例不是更改主容器的不透明度,而是更改 rgb 值。这就是背景颜色平滑过渡的原因。而您直接使用不透明动画提供颜色值,因此整个容器都会受到影响。所以不要改变容器的不透明度。

    【讨论】:

    • 所以你的意思是项目示例中的容器背景不做任何过渡?它只是改变 rgb 值?
    • 但似乎容器背景也做了过渡。如果我只更改容器的 rgb 值但不包含动画,则不会像示例中那样获得淡入过渡
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 2013-02-10
    • 2020-11-15
    相关资源
    最近更新 更多