用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               width: '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           width: '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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM