zoukankan      html  css  js  c++  java
  • 用react的ReactCSSTransitionGroup插件实现简单的弹幕动画

    1,开始的思路

    公司想做直播方面的项目,并想加入弹幕的功能,直播的页面已经作为一个组件放在了用react+redux写好的一个网站项目上。
    所以技术老大让我研究下如何用react实现弹幕的功能。下面我就简单说下我的react弹幕折腾之路。
    一开始其实是两手空空,作为一个php的初级开发人员,我对前端技术掌握的很少,远不到熟练的程度。所以,我得从头学习如何用js+css实现弹幕,然后再将弹幕移植到react项目上去,这是我一开始的思路。

    2,中间的折腾

    我百度了下“js 弹幕”,发现大部分都是用jquery的animate()函数和css配合来实现的,比如这个HTML+CSS+jQuery实现弹幕技术,有些则是jquery配合css的animation来实现。
    我学习了下用jquery的animate()函数配合css来实现弹幕的方法,然后就尝试将这个方法引入到react项目中去。但我在这个地方费了好多时间都没有进展,最终我放弃了将jquery引入react的想法。技术老大提醒我,可以找找react动画的解决方法。
    于是百度、google,在sgemenfault和知乎上有不少问答,给出了三个解决方向:
    1,用react官方提供的动画插件(ReactCSSTransitionGroup)可以实现基本和简单的动画
    2,引入专业的第三方的动画库
    3,用第三方的react动画插件
    第1种方法,简单、直接,需要对react的动画插件有所了解,第2种方法需要非常熟悉第三方库的用法,像我这种前端的半吊子还是算了:),第3种方法,我也没考虑。
    总之,我选择了第1种。我大致看了下react官方的tutorial和docs,然后就开始动手了。

    3,初现曙光

    按照react官网上给的TodoList例子,我写出了我的第1个react动画(没有用到redux),

    实现的基本功能就是在一个输入框中输入文字,然后enter发送文字,文字从一个div的右侧走到左侧,最后消失。先把代码贴出来:

    点击我查看代码
      1 import React from 'react';
      2 import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
      3 
      4 class App extends React.Component {
      5   constructor(props) {
      6     super(props);
      7     this.state = {
      8       word: '',
      9       value: '',
     10       index: 0,
     11       top: 0,
     12     };
     13     this.returnWord = this.returnWord.bind(this);
     14     this.handleChange = this.handleChange.bind(this);
     15     this.handleSubmit = this.handleSubmit.bind(this);
     16   }
     17 
     18   componentDidMount() {
     19     // 监听回车事件
     20     document.onkeydown = (event) => {
     21       if (event.keyCode === 13) {
     22         document.getElementById('sendBullet').click = null;
     23       }
     24     };
     25   }
     26 
     27   handleSubmit(event) {
     28     event.preventDefault();
     29     this.setState({ value: '' });
     30   }
     31 
     32   handleChange(event) {
     33     this.setState({ value: event.target.value });
     34   }
     35 
     36   returnWord() {
     37     const word = this.myTextInput;
     38     const index = this.state.index;
     39     const top = this.state.top;
     40     if (word === this.state.value) {
     41       this.setState({ word, index: index + 1 });
     42     }
     43     if (top <= 435) {
     44       this.setState({ top: top + 75 });
     45     } else if (top > 435) {
     46       this.setState({ top: 0 });
     47     }
     48   }
     49 
     50   render() {
     51     const item = (
     52       <div
     53         className="bullet"
     54         key={this.state.index}
     55         style={{ top: `${this.state.top}px`, color: `#${((1 << 24) * Math.random() | 0).toString(16)}` }}
     56       >
     57         {this.state.word}
     58       </div>
     59     );
     60 
     61     return (
     62       <div>
     63         <form onSubmit={this.handleSubmit}>
     64           <input
     65             type="text"
     66             ref={
     67               (ref) => {
     68                 if (ref !== null && ref.value.trim() !== '') {
     69                   this.myTextInput = ref.value;
     70                 }
     71               }
     72             }
     73             value={this.state.value}
     74             onChange={this.handleChange}
     75           />
     76         <button id="sendBullet" onClick={this.returnWord}>发送弹幕</button>
     77           <div
     78             style={{
     79               position: 'relative',
     80                '1200px',
     81               height: '500px',
     82               margin: 'auto',
     83               background: 'rgba(255, 0, 0, 0.1)',
     84               overflow: 'hidden',
     85             }}
     86           >
     87             <ReactCSSTransitionGroup
     88               transitionName={{
     89                 enter: 'bullet-enter',
     90               }}
     91               transitionEnterTimeout={5000}
     92               transitionLeave={false}
     93             >
     94               {item}
     95             </ReactCSSTransitionGroup>
     96           </div>
     97         </form>
     98       </div>
     99     );
    100   }
    101 }
    102 
    103 export default App;

    可以看到我这里引入了ReactCSSTransitionGroup它是react提供的一个动画插件,可以实现基本、简单的css动画和渐变功能,它需要单独安装,具体的安装方法可以百度或google。

    下面来说下比较关键的地方:

    1,代码第51~59行,定义要动的弹幕文字组件。 render方法中定义了一个item,这个item就是弹幕中要动起来的弹幕文字组件。要注意:item中的key属性是必须要给定的,哪怕你只有单独的1个item也要指定key,

    这样React才能决定哪个item该如何动作,这也是react官方文档中所强调的。我定义了自增的index作为state来管理item的key,这样每个item都有一个唯一的key。

    2,代码第87~95行,ReactCSSTransitionGroup配置。需要注意的是,一定要将要操纵的动画元素完全包含到ReactCSSTransitionGroup中去,然后就是根据动画需要设置要做的动画过程。我只要入场动画(有字幕出现时就开始动画)就可以了。

    所以设置入场动画时间transitionEnterTimeout={5000}。另外,出场动画不需要可以设置为false: transitionLeave={false},不能忽略这个属性,不然会报错。transitionName中可以设置动画过程的css样式名称,设置规则可参考官网。

    3,下面是我的入场动画css样式,也是要注意的第3点

     1 .bullet {
     2   opacity: 0.01;
     3 }
     4 
     5 .bullet-enter {
     6   opacity: 1;
     7   position: absolute;
     8   left: 1100px;
     9 }
    10 
    11 .bullet-enter.bullet-enter-active {
    12   opacity: .5;
    13   position: absolute;
    14   left: -100px;
    15   transition: all 5000ms ease-in;
    16 }
    View Code

    .bullet-enter对应入场动画开始时的item样式,.bullet-enter.bullet-enter-active对应入场动画结束时的item样式,可以看到用到了css的transition,这也是实现动画的关键。

    以上3点比较关键,其余的问题就是如何产生item的问题,这个暂时先不写了。

    4,将弹幕作为一个组件整合到react+redux项目中

    其实只要实现了弹幕动画,整合也就容易了,下面先把弹幕组件的代码贴出来。

     1 import React, { Component, PropTypes } from 'react';
     2 import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
     3 
     4 class BulletScreen extends Component {
     5 
     6   render() {
     7     const item = (
     8       <div
     9         className="bullet"
    10         key={this.props.index}
    11         style={{
    12           top: `${this.props.top}vh`,
    13           color: 'rgb(255, 255, 255)',
    14           whiteSpace: 'nowrap',
    15           fontSize: '3vh',
    16         }}
    17       >
    18         {this.props.word}
    19       </div>
    20     );
    21 
    22     return (
    23       <div
    24         id="bullt-screen"
    25         style={{
    26           position: 'relative',
    27            'auto',
    28           height: '46vh',
    29           overflow: 'hidden',
    30           margin: '-50vh auto auto auto',
    31           background: 'rgba(0, 255, 0, 0.01)',
    32         }}
    33       >
    34         <ReactCSSTransitionGroup
    35           transitionName={{
    36             enter: 'bullet-enter',
    37           }}
    38           transitionEnterTimeout={5000}
    39           transitionLeave={false}
    40         >
    41           {item}
    42         </ReactCSSTransitionGroup>
    43       </div>
    44     );
    45   }
    46 }
    47 
    48 BulletScreen.propTypes = {
    49   word: PropTypes.string,
    50   index: PropTypes.number,
    51   top: PropTypes.number,
    52 };
    53 
    54 export default BulletScreen;
    View Code

    到时在视频播放的页面中引入这个组件就可以了。

    这个项目目前是我司的开源项目,感兴趣的朋友可以去github上看下: wecan-tv-frontend

    参考资料:
    HTML+CSS+jQuery实现弹幕技术
    Animation Add-Ons

  • 相关阅读:
    Ethical Hacking
    Ethical Hacking
    Ethical Hacking
    National Treasures HDU
    Matrix HDU
    过山车 HDU
    Jimmy’s Assignment HDU
    Card Game Cheater HDU
    Uncle Tom's Inherited Land* HDU
    50 years, 50 colors HDU
  • 原文地址:https://www.cnblogs.com/yangtoude/p/5987958.html
Copyright © 2011-2022 走看看