首页 > 网站 > WEB开发 > 正文

实战React音乐播放器

2024-04-27 15:05:28
字体:
来源:转载
供稿:网友

上篇文章《一步一步实战HTML音乐播放器》中,我用HTML+JS + CSS的方式一步步实现了一个音乐播放器,因为最近接触了一下React,感觉挺不错的,在这里我用React的方式实现一个同样的音乐播放器。


播放器功能

自动显示 专辑图片、歌手名、歌曲名、专辑名显示播放器进度条音乐播放暂停、上一曲、下一曲实时显示播放时间、播放总长度歌曲播放完后,自动切换下一曲

播放器效果


React 环境准备

在这个小项目中,不再使用传统的构建React的方式来搭建环境了,这里用一种很方便的小工具来实现环境的搭建。

在Node.js环境下执行如下命令,安装一下create-react-app,并创建musicPlayer项目:

npm install -g create-react-appcreate-react-app musicPlayercd musicPlayernpm start

执行完后后,工具会自动打开浏览器来显示这个项目的内容,效果如下:

这里我用到的是src目录,首先把src目录的内容全部删除,我们一点一点的来编写项目代码。


引入必要文件

因为系统默认将index.js作为入口文件,所以我们要先在src下创建index.js文件,所有代码也是在这个文件中编写。

先在index.js中引入一些必要的文件:

import React from 'react';import ReactDOM from 'react-dom';import './index.min.css';

index.min.css是播放器的样式文件,这里主要说React,这个样式文件的详细说明可以参考 《一步一步实战HTML音乐播放器》


创建播放器容器组件

var Player = React.createClass({ render: function() { return ( <div className="player"> {/* 各类子组建…… */} </div> ); }});

子组建我们下面会一一创建,这里先用做一下占位说明。


页面渲染

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

容器内的各类组件

根据播放器结构,创建如下组件:

var Player = React.createClass({ render: function() { return ( <div className="player"> {/* 播放器名称 */} <div className="header">音乐播放器.React版</div> {/* 音乐信息 */} <TrackInfo /> {/* 播放进度条 */} <PRogress /> {/* 播放控制 */} <Controls /> {/* 播放时间 */} <Time /> {/* 音频控件 */} <audio id="audio"></audio> </div> ); }});

初始化STATE,PROPS

根据需求,进行状态和属性的创建。

这里歌单就手动制作一个了,把这个歌单写的props中,用于系统的调用:

getDefaultProps: function() { //歌单列表 return{ "tracks": [ { "name": "元日", "artists": [ { "name": "于文华", } ], "album": { "name": "国学唱歌集", "picUrl": "http://p3.music.126.net/SR9eFEjRB0NsscxN7-fHMw==/3344714372906000.jpg", }, "duration": 136829, "mp3Url": "http://m2.music.126.net/rUcfQQZbq7TIfJeAHfTrkw==/3376600210116829.mp3" }, { "name": "元日 ", "artists": [ { "name": "清弄", } ], "album": { "name": "热门华语261", "picUrl": "http://p4.music.126.net/ly2FJHh5-lYMdC3NZxvavQ==/7714173580661848.jpg", }, "duration": 109000, "mp3Url": "http://m2.music.126.net/jwwZVlWJ78HEarft42uKUQ==/7906588115920636.mp3" }, { "name": "青龙·花木苍苍", "artists": [ { "name": "五色石南叶", } ], "album": { "name": "热门华语234", "picUrl": "http://p4.music.126.net/tHAfnugCElS93EDp5cHLIw==/8909342719897560.jpg", }, "duration": 295575, "mp3Url": "http://m2.music.126.net/rnq_W32zFX_utQbBhE0xkg==/8934631487358481.mp3" }] } },

接着初始化一下播放器的状态:

//初始化状态 getInitialState: function() { return{ currentTrackLen: this.props.tracks.length, //歌单歌曲数 currentTrackIndex: 0, //当前播放的歌曲索引,默认加载第一首歌 currentTime: 0, //当前歌曲播放的时间 currentTotalTime: 0, //当前歌曲的总时间 playStatus: true, //true为播放状态,false为暂停状态 } },

创建子组件

TrackInfo组件

var TrackInfo = React.createClass({ render: function() { return( <div> <div className="albumPic" style={{'backgroundImage':'url('+ this.props.track.album.picUrl +')'}}></div> <div className='trackInfo'> <div className="name">{this.props.track.name}</div> <div className="artist">{this.props.track.artists[0].name}</div> <div className="album">{this.props.track.album.name}</div> </div> </div> ); }});

Player容器中的标签修改为:

{/* 音乐专辑 */}<TrackInfo track={this.props.tracks[this.state.currentTrackIndex]} />

Progress组件

var Progress = React.createClass({ render: function(){ return ( <div className="progress" style={{'width':this.props.progress}}></div> ) }});

Player容器中的标签修改为:

{/* 播放进度条 */}<Progress progress={this.state.currentTime / this.state.currentTotalTime * 100 + '%'} />

通过当前时间和总时间来计算播放百分百。

Controls组件

var Controls = React.createClass({ render: function(){ let className; if(this.props.isPlay == true){ className = 'icon-pause'; }else{ className = 'icon-play'; } return ( <div className="controls"> <div className="play" onClick={this.props.onPlay}> <i className={className}></i> </div> <div className="previous" onClick={this.props.onPrevious}> <i className="icon-previous"></i> </div> <div className="next" onClick={this.props.onNext}> <i className="icon-next"></i> </div> </div> ) }});

通过isPlay来控制播放按钮图标的显示。

Player容器中的标签修改为:

{/* 播放控制 */}<Controls isPlay={this.state.playStatus} onPlay={this.play} onPrevious={this.previous} onNext={this.next} />

Time组件

var Time = React.createClass({ timeConvert: function(timestamp){ var minutes = Math.floor(timestamp / 60); var seconds = Math.floor(timestamp - (minutes * 60)); if(seconds < 10) { seconds = '0' + seconds; } timestamp = minutes + ':' + seconds; return timestamp; }, render:function() { return( <div className="time"> <div className="current">{this.timeConvert(this.props.currentTime)}</div> <div className="total">{this.timeConvert(this.props.currentTotalTime)}</div> </div> ); }});

timeConvert做为一个时间转换显示来用。

Player容器中的标签修改为:

{/* 播放时间 */}<Time currentTime={this.state.currentTime} currentTotalTime={this.state.currentTotalTime} />

audio标签

audio这里不需要在创建组件了,修改一下在Player中的标记就行:

{/* 音频控件 */}<audio id="audio" src={this.props.tracks[this.state.currentTrackIndex].mp3Url}></audio>

事件处理方法

创建updatePlayStatus方法用于更新播放器的状态:

//更新播放状态 updatePlayStatus: function(){ let audio = document.getElementById('audio'); if(this.state.playStatus){ audio.play(); }else{ audio.pause(); } //更新当前歌曲总时间 this.setState({currentTotalTime: this.props.tracks[this.state.currentTrackIndex].duration / 1000}); },

创建三个播放控制按钮的事件方法:

//播放事件处理 play:function(){ //这里有setState是异步的,需要在回调中执行 this.setState({playStatus:!this.state.playStatus}, ()=>{ this.updatePlayStatus(); }); }, //上一曲事件处理 previous:function(){ if(this.state.currentTrackIndex - 1 < 0){ alert('已经没有上一首了'); }else{ this.setState({currentTrackIndex:--this.state.currentTrackIndex},()=>{ this.updatePlayStatus(); }); } }, //下一曲事件处理 next:function(){ if(this.state.currentTrackIndex + 1 >= this.state.currentTrackLen){ alert('已经没有下一首了'); }else{ this.setState({currentTrackIndex:++this.state.currentTrackIndex},()=>{ this.updatePlayStatus(); }); } },

在页面渲染完成后需要执行一下updatePlayStatus方法,根据React生命周期,我们在DOM加载完成后执行一下这个方法:

componentDidMount: function(){ this.updatePlayStatus(); },

好了,各类事件的方法基本完成,这里还需要一个监测的方法,用来实时更新播放时间和自动下一曲:

componentDidMount: function(){ this.updatePlayStatus(); setInterval(()=>{ let audio = document.getElementById('audio'); this.setState({currentTime:audio.currentTime},()=>{ if(~~this.state.currentTime >= ~~this.state.currentTotalTime){ this.next(); } }); }, 300); },

完整代码

//index.jsimport React from 'react';import ReactDOM from 'react-dom';import './index.min.css';var Player = React.createClass({ getDefaultProps: function() { //歌单列表 return{ "tracks": [ { "name": "元日", "artists": [ { "name": "于文华", } ], "album": { "name": "国学唱歌集", "picUrl": "http://p3.music.126.net/SR9eFEjRB0NsscxN7-fHMw==/3344714372906000.jpg", }, "duration": 136829, "mp3Url": "http://m2.music.126.net/rUcfqqZbq7TIfJeAHfTrkw==/3376600210116829.mp3" }, { "name": "元日 ", "artists": [ { "name": "清弄", } ], "album": { "name": "热门华语261", "picUrl": "http://p4.music.126.net/ly2FJHh5-lYMdC3NZxvavQ==/7714173580661848.jpg", }, "duration": 109000, "mp3Url": "http://m2.music.126.net/jwwZVlWJ78HEarft42uKUQ==/7906588115920636.mp3" }, { "name": "青龙·花木苍苍", "artists": [ { "name": "五色石南叶", } ], "album": { "name": "热门华语234", "picUrl": "http://p4.music.126.net/tHAfnugCElS93EDp5cHLIw==/8909342719897560.jpg", }, "duration": 295575, "mp3Url": "http://m2.music.126.net/rnq_W32zFX_utQbBhE0xkg==/8934631487358481.mp3" }] } }, //初始化状态 getInitialState: function() { return{ currentTrackLen: this.props.tracks.length, //歌单歌曲数 currentTrackIndex: 0, //当前播放的歌曲索引,默认加载第一首歌 currentTime: 0, //当前歌曲播放的时间 currentTotalTime: 0, //当前歌曲的总时间 playStatus: true, //true为播放状态,false为暂停状态 } }, //更新播放状态 updatePlayStatus: function(){ let audio = document.getElementById('audio'); if(this.state.playStatus){ audio.play(); }else{ audio.pause(); } //更新当前歌曲总时间 this.setState({currentTotalTime: this.props.tracks[this.state.currentTrackIndex].duration / 1000}); }, //播放事件处理 play:function(){ //这里有setState是异步的,需要在回调中执行 this.setState({playStatus:!this.state.playStatus}, ()=>{ this.updatePlayStatus(); }); }, //上一曲事件处理 previous:function(){ if(this.state.currentTrackIndex - 1 < 0){ alert('已经没有上一首了'); }else{ this.setState({currentTrackIndex:--this.state.currentTrackIndex},()=>{ this.updatePlayStatus(); }); } }, //下一曲事件处理 next:function(){ if(this.state.currentTrackIndex + 1 >= this.state.currentTrackLen){ alert('已经没有下一首了'); }else{ this.setState({currentTrackIndex:++this.state.currentTrackIndex},()=>{ this.updatePlayStatus(); }); } }, //DOM加载完 componentDidMount: function(){ this.updatePlayStatus(); setInterval(()=>{ let audio = document.getElementById('audio'); this.setState({currentTime:audio.currentTime},()=>{ if(~~this.state.currentTime >= ~~this.state.currentTotalTime){ this.next(); } }); }, 300); }, render: function() { return ( <div className="player"> {/* 播放器名称 */} <div className="header">音乐播放器.React版</div> {/* 音乐信息 */} <TrackInfo track={this.props.tracks[this.state.currentTrackIndex]} /> {/* 播放进度条 */} <Progress progress={this.state.currentTime / this.state.currentTotalTime * 100 + '%'} /> {/* 播放控制 */} <Controls isPlay={this.state.playStatus} onPlay={this.play} onPrevious={this.previous} onNext={this.next} /> {/* 播放时间 */} <Time currentTime={this.state.currentTime} currentTotalTime={this.state.currentTotalTime} /> {/* 音频控件 */} <audio id="audio" src={this.props.tracks[this.state.currentTrackIndex].mp3Url}></audio> </div> ); }});var TrackInfo = React.createClass({ render: function() { return( <div> <div className="albumPic" style={{'backgroundImage':'url('+ this.props.track.album.picUrl +')'}}></div> <div className='trackInfo'> <div className="name">{this.props.track.name}</div> <div className="artist">{this.props.track.artists[0].name}</div> <div className="album">{this.props.track.album.name}</div> </div> </div> ); }});var Progress = React.createClass({ render: function(){ return ( <div className="progress" style={{'width':this.props.progress}}></div> ) }});var Controls = React.createClass({ render: function(){ let className; if(this.props.isPlay == true){ className = 'icon-pause'; }else{ className = 'icon-play'; } return ( <div className="controls"> <div className="play" onClick={this.props.onPlay}> <i className={className}></i> </div> <div className="previous" onClick={this.props.onPrevious}> <i className="icon-previous"></i> </div> <div className="next" onClick={this.props.onNext}> <i className="icon-next"></i> </div> </div> ) }});var Time = React.createClass({ timeConvert: function(timestamp){ var minutes = Math.floor(timestamp / 60); var seconds = Math.floor(timestamp - (minutes * 60)); if(seconds < 10) { seconds = '0' + seconds; } timestamp = minutes + ':' + seconds; return timestamp; }, render:function() { return( <div className="time"> <div className="current">{this.timeConvert(this.props.currentTime)}</div> <div className="total">{this.timeConvert(this.props.currentTotalTime)}</div> </div> ); }});ReactDOM.render( <Player />, document.getElementById('root'));

发布项目

在Node.js环境下执行:

npm run build

进行代码打包处理,打包文件生成了项目目录下的build中,执行如下命令,可直接查看build打包后的内容:

npm install -g pushstate-serverpushstate-server build

浏览器中输入如下地址:http://localhost:9000


好了,用React来实现音乐播放器彻底完成,因为React我也是刚接触不久,代码中可能存在着缺点,我这里就抛砖引玉了。

总体来说,用React的思想来做东西,确实挺好的,逻辑上也变得比较清晰。

React 音乐播放器代码下载:代码下载


博客名称:王乐平博客

博客地址:http://blog.lepingde.com

CSDN博客地址:http://blog.csdn.net/lecepin


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表