实战React音乐播放器

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


播放器功能

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

播放器效果


React 环境准备

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

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

npm install -g create-react-app
create-react-app musicPlayer
cd musicPlayer
npm 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.js
import 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-server
pushstate-server build

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



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

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

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


博客名称:王乐平博客

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

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

时间: 2024-08-05 06:49:10

实战React音乐播放器的相关文章

一步一步实战HTML音乐播放器

在这里我用HTML5从头开始一步一步来制作一个简约的音乐播放器,大家可以参考一下,接下来正式开始. 音乐播放器效果 播放器分析 这里将播放器分两块来做: 视图层(html + css) 逻辑层 ( js ) 视图层分析 视图中包含: 播放器容器 播放器名称 音乐专辑图 音乐信息 歌曲名 歌手 专辑名 控制区 上一曲 播放 下一曲 播放进度条 播放时间 当前时间 歌曲总时间 音频控件 页面背景 逻辑层分析 逻辑层处理包括: 加载歌单 渲染歌曲信息 专辑图 歌曲名 歌手 专辑名 歌曲时长 歌曲音频地

个人搭建的React项目之React音乐播放器

该项目是本人自使用react框架以来制作的较大的项目,目前该项目放在github上,感兴趣的朋友可以去看看一下,觉得还行的话可以给个star,哈哈 地址:https://github.com/cocoxiaoyue/react-music-player 项目环境 运行 1.该项目是基于node环境,通过create-react-app搭建的react项目,所以该项目应在装有node的机器上运行. 2.该项目运用的是网易云音乐接口,所以应该下载网易云音乐接口项目https://github.com

Android Fragment应用实战(音乐播放器界面)

当下很多手机应用都会有一个非常类似的功能,即屏幕的下方显示一行Tab标签选项,点击不同的标签就可以切换到不同的界面,如以下几个应用所示: 以上底部这四个标签,每一个分别对应一个Fragment,这种底部标签式的布局策略真的非常常见,那么话说回来,这种效果到底是如何的呢?熟悉Android的朋友一定都会知道,很简单嘛,使用TabHost就OK了!但是殊不知,TabHost并非是那么的简单,它的可扩展性非常的差,不能随意地定制Tab项显示的内容,而且运行还要依赖于ActivityGroup.Acti

蓝懿IOS实战音乐播放器

今天刘国斌老师教了实战的一个demo,仿写音乐播放器 // 1. 如果在viewcontroller里跳转到别的页面里,另一个viewcontroller是storyboard拖出来的,初始化页面需要用self.stroy 再调用方法,instantiateViewControllerWithIdentifier // 2. 但是如果在其他的页面不是viewcontroller里再跳转到另一个页面,那个页面也是用stroyboard拖出来的,那么就要用 UIStoryboard 通过自己的mai

HTML5之audio实战,网页音乐播放器开发

今天我们就基于 HTML5 audio  来,开发一个网页音乐播放器. 在HTML5 新特性中,audio .video 是我们比较关心的 新 元素,我们终于可以脱离 Flash ,来开发音频.视频播放器了,对于 一个HTML 新元素,无非就是 属性.事件 .方法等等,关于audio 的具体的属性.事件 .方法,请谷歌. 看我们的HTML代码: audio.html <!DOCTYPE html> <html> <head> <meta charset="

React Native (一) react-native-video实现音乐播放器和进度条的功能

React Native (一) react-native-video实现音乐播放器和进度条的功能 功能: 1.卡片滑动切歌 2.显示进度条 效果图: 第三方组件: 1.react-native-video Github地址:https://github.com/react-native-community/react-native-video 2.react-native-animated-tabs Github地址:https://github.com/philipshurpik/react

Android开发实战之简单音乐播放器

最近开始学习音频相关.所以,很想自己做一个音乐播放器,于是,花了一天学习,将播放器的基本功能实现了出来.我觉得学习知识点还是蛮多的,所以写篇博客总结一下关于一个音乐播放器实现的逻辑.希望这篇博文对你的学习和生活有所帮助.效果图: **实现逻辑** 在市面上的音乐播放app,即时你关了.那么一样会在后台播放,所以播放的逻辑应该写在Service中.并且能够实现Service和Activity之间进行通信.那么Service是四大组件之一,所以在使用的时候一定不要忘了在配置文件中声明一下. <ser

Andriod小项目——在线音乐播放器

Android在线音乐播放器 从大一开始就已经开始自学Java和Android了,到现在差不多有一年了. 终于到了开始做项目实战的阶段了.就先DIY个在线音乐播放器. 实现了以下功能: 这个播放器可以从本机电脑搭建的简易服务器里异步读取并解析json数据,播放音乐,实现音乐切换,时间显示,以及显示播放进度. 程序有三个界面,启动画面,音乐列表,播放器页面,可以通过音乐列表点击进入到播放界面. 这篇文章只大概写了一下实现的思路,描述了一些关键的地方. 文章最后还提供了源代码,可以在文章结尾处  下

Android实现音乐播放器(一)

Graphical User Interface 本篇文章记录了我实现Android简单音乐播放器的过程,(一)中介绍了怎么构建音乐播放器的前端页面.首先大家看一下,界面最后是这样的(界面有点粗陋) 音乐文件列表是从SD卡中读取出来的. 首先我们先在Layout里面创建Music Player的GUI,diagram如下图所示: 根据diagram我们在activity_main.xml写出如下代码: <LinearLayout xmlns:android="http://schemas.