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的右侧走到左侧,最后消失。先把代码贴出来:

点击我查看代码

 import React from 'react';
 import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

 class App extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       word: '',
       value: '',
       index: 0,
       top: 0,
     };
     this.returnWord = this.returnWord.bind(this);
     this.handleChange = this.handleChange.bind(this);
     this.handleSubmit = this.handleSubmit.bind(this);
   }

   componentDidMount() {
     // 监听回车事件
     document.onkeydown = (event) => {
       if (event.keyCode === 13) {
         document.getElementById('sendBullet').click = null;
       }
     };
   }

   handleSubmit(event) {
     event.preventDefault();
     this.setState({ value: '' });
   }

   handleChange(event) {
     this.setState({ value: event.target.value });
   }

   returnWord() {
     const word = this.myTextInput;
     const index = this.state.index;
     const top = this.state.top;
     if (word === this.state.value) {
       this.setState({ word, index: index + 1 });
     }
     if (top <= 435) {
       this.setState({ top: top + 75 });
     } else if (top > 435) {
       this.setState({ top: 0 });
     }
   }

   render() {
     const item = (
       <div
         className="bullet"
         key={this.state.index}
         style={{ top: `${this.state.top}px`, color: `#${((1 << 24) * Math.random() | 0).toString(16)}` }}
       >
         {this.state.word}
       </div>
     );

     return (
       <div>
         <form onSubmit={this.handleSubmit}>
           <input
             type="text"
             ref={
               (ref) => {
                 if (ref !== null && ref.value.trim() !== '') {
                   this.myTextInput = ref.value;
                 }
               }
             }
             value={this.state.value}
             onChange={this.handleChange}
           />
         <button id="sendBullet" onClick={this.returnWord}>发送弹幕</button>
           <div
             style={{
               position: 'relative',
               width: '1200px',
               height: '500px',
               margin: 'auto',
               background: 'rgba(255, 0, 0, 0.1)',
               overflow: 'hidden',
             }}
           >
             <ReactCSSTransitionGroup
               transitionName={{
                 enter: 'bullet-enter',
               }}
               transitionEnterTimeout={5000}
               transitionLeave={false}
             >
               {item}
             </ReactCSSTransitionGroup>
           </div>
         </form>
       </div>
     );
   }
 }

 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点

 .bullet {
   opacity: 0.01;
 }

 .bullet-enter {
 ;
   position: absolute;
   left: 1100px;
 }

 .bullet-enter.bullet-enter-active {
   opacity: .5;
   position: absolute;
   left: -100px;
   transition: all 5000ms ease-in;
 }

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

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

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

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

 import React, { Component, PropTypes } from 'react';
 import ReactCSSTransitionGroup from 'react-addons-css-transition-group';

 class BulletScreen extends Component {

   render() {
     const item = (
       <div
         className="bullet"
         key={this.props.index}
         style={{
           top: `${this.props.top}vh`,
           color: 'rgb(255, 255, 255)',
           whiteSpace: 'nowrap',
           fontSize: '3vh',
         }}
       >
         {this.props.word}
       </div>
     );

     return (
       <div
         id="bullt-screen"
         style={{
           position: 'relative',
           width: 'auto',
           height: '46vh',
           overflow: 'hidden',
           margin: '-50vh auto auto auto',
           background: 'rgba(0, 255, 0, 0.01)',
         }}
       >
         <ReactCSSTransitionGroup
           transitionName={{
             enter: 'bullet-enter',
           }}
           transitionEnterTimeout={5000}
           transitionLeave={false}
         >
           {item}
         </ReactCSSTransitionGroup>
       </div>
     );
   }
 }

 BulletScreen.propTypes = {
   word: PropTypes.string,
   index: PropTypes.number,
   top: PropTypes.number,
 };

 export default BulletScreen;

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

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

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

用react的ReactCSSTransitionGroup插件实现简单的弹幕动画的更多相关文章

  1. Xcode7使用插件的简单方法&amp;&amp;以及怎样下载到更早版本的Xcode

    Xcode7自2015年9上架以来也有段时间了, 使用Xcode7以及Xcode7.1\Xcode7.2的小伙伴会发现像VVDocumenter-Xcode\KSImageNamed-Xcode\HO ...

  2. 移动端全屏滑动的小插件,简单,轻便,好用,只有3k swiper,myswiper,page,stage

    https://github.com/donglegend/mySwiper mySwiper 移动端全屏滑动的小插件,简单,轻便,好用,只有3k 下载 直接下载 bower install mySw ...

  3. 数据统计表插件,highcharts插件的简单应用

    highcharts插件的简单应用,非常全能好用的一个数据统计表插件. $(function () { $('#container').highcharts({ chart:{ type:" ...

  4. ASP.NET MVC5 插件机制中插件的简单实现

    Autofac 依赖注入 ASP.NET MVC5 插件机制中插件的简单实现 一.前言 由于项目业务复杂,创建了多个插件并把他们放在了不同的项目中,项目使用AutoFac做的IOC:但是主项目可以注入 ...

  5. Atom编辑器之加快React开发的插件汇总

    汇总下比较实用的atom插件[偏react开发的]-- 博主发现这个还是比较全面的! atom-react-autocomplete–项目内,组件名及状态的自动补全  autocomplete-js- ...

  6. swiper插件的简单使用,实现图片轮播

    移动端和p c端经常会遇到写轮播图的情况,这里只是简单的说一下swiper插件的简单用法(移动端为例). <!DOCTYPE html> <html lang="en&qu ...

  7. 基于jquery fly插件实现加入购物车抛物线动画效果,jquery.fly.js

    在购物网站中,加入购物车的功能是必须的功能,有的网站在用户点击加入购物车按钮时,就会出现该商品从点击出以抛物线的动画相似加入购物车,这个功能看起来非常炫,对用户体验也有一定的提高.下面介绍基于jque ...

  8. Android简单逐帧动画Frame的实现(二)

    Android简单逐帧动画Frame的实现   Android简单逐帧动画Frame的实现 1.逐帧动画 即是通过播放预先排序好的图片来实现动态的画面,感觉像是放电影. 2.实现步骤: 1. 在工程里 ...

  9. 【UI插件】简单的日历插件(下)—— 学习MVC思想

    前言 我们上次写了一个简单的日历插件,但是只是一个半成品,而且做完后发现一些问题,于是我们今天尝试来解决这些问题 PS:距离上次貌似很久了 上次,我们大概遇到哪些问题呢: ① 既然想做一套UI库,那么 ...

随机推荐

  1. 一位同事对 Rafy 框架的一些建议及我的回复

    下面是一位同事对当前的产品开发框架提出的一些建议,以及我的回复.我觉得一些问题提得有一定的代表性,在征得本人同意后,将本邮件发布在博客中. 同时,也非常希望对框架.产品有好的建议的小伙伴,都可以给我发 ...

  2. python2.7 学习笔记--列表的使用

    同其它编程语言一样,python也提供了丰富的数据结构,以方便数据的处理.本文介绍两种最基本的数据集合,列表和元组的使用. 一.列表使用介绍 可以理解为一个有序的序列.其使用方式举例如下: list= ...

  3. 转: javascript实现全国城市三级联动菜单代码

    <html> <head> <title>js全国城市三级联动菜单代码_B5教程网</title> <meta http-equiv=" ...

  4. Python跳过第一行读取文件内容

    Python编程时,经常需要跳过第一行读取文件内容.比较容易想到是为每行设置一个line_num,然后判断line_num是否为1,如果不等于1,则进行读取操作.相应的Python代码如下: inpu ...

  5. 动态切换采用 CSplitterWnd 静态划分的视图布局(MFC)

    标题读起来有些拗口,具体是什么情况,我们来看: 一.问题的提出 一个采用MFC开发的软件,其窗体视图采用CSplitterWnd三分,效果如下图所示: 图1 软件的默认视图布局 该MFC开发的软件功能 ...

  6. 在Jmeter中使用自定义编写的Java测试代码

    我们在做性能测试时,有时需要自己编写测试脚本,很多测试工具都支持自定义编写测试脚本,比如LoadRunner就有很多自定义脚本的协议,比如"C Vuser","Java ...

  7. mkdir -p命令

    如果要创建目录A并创建目录A的子目录B,没有用-p的情况下是mkdir 2次如果用-p 可以直接创建2个目录 mkdir -p 目录A/子目录B就可以

  8. Form实现主从块金额汇总

    1.FORM使用app_calculate.running_total汇总行金额,行上有编码重复验证. 情况一:当录入多个编码重复的行并保存时,报错,清除一个重复行再保存(头行金额一致),报错&quo ...

  9. FSG1.33解压缩算法分析

    之前只是知道怎样脱去fsg壳,对壳的压缩算法没有太多的注意,今天就对算法进行一些分析 使用的版本是fsg1.33,首先用peid查壳: 2.将程序载入OD,看到如下代码 可以看到这段代码主要是从以es ...

  10. Android:Notification的生成与取消

    MainActivity.java: package com.example.notificationdemo; import android.app.Activity; import android ...