2

使用Howl和SiriWave制作一个高逼格的音频播放功能(非常适合手机端)

阿北 2月27日 发布于前端 www.learn-tips.com

最近在一个外包项目中涉及到了移动页面音频播放需求,这个功能在自媒体中被广泛使用,最明显的比如现在微信订阅号文章的音频插入,在此将使用库和实现逻辑分享出来,希望对你有用。

使用Howl和SiriWave制作一个高逼格的音频播放功能(非常适合手机端)

2月27日 发布,来源:www.learn-tips.com

最近在一个外包项目中涉及到了移动页面音频播放需求,这个功能在自媒体中被广泛使用,最明显的比如现在微信订阅号文章的音频插入,在此将使用库和实现逻辑分享出来,希望对你有用。

当然你完全可以使用h5接口直接播放,但是我们希望这个音频的体验更好,很简单,只需要借助于两个开源的js库。

实现功能&准备

我们先来规划下要实现的功能

  • 支持一个音频及多个视频播放功能。
  • 支持音频暂停和播放,并有波纹显示。
  • 支持音频自动连续播放功能。

开始啦。

我们准备两条记录,分别为a.mp3和b.mp3,将其嵌入到一个页面中并实现上述功能,这里你可能看到一些yii2的语法,不过不要害怕,它们非常简单,并且其实你要看的重点在js上。

音频标题 音频路径 备注
李白送汪伦 /uploads/a.mp3
长恨歌 /uploads/b.mp3

Howler播放音频

H5提供了音频接口,我们只需要简单的代码就可以实现

<audio src="/uploads/a.mp3"></audio>

语法简单,但是缺点是可制定性差一些。

因此我放弃了直接使用h5的audio标签,而是采用Howler来解决上面问题。Howler是一个现代的音频播放库并且支持回调,我们可以在每个回调函数中写入自己的逻辑,当然它的优点还有很多,具体请看官方说明文档

下面我们使用 Howler 来播放一条音频。

var sound = new Howl({
    src: ['/uploads/a.mp3'],
    html5: true
});

sound.play();// 开始播放

当然上面的代码对我来说是不够的,我们需要在页面上有一个区域来显示音频的播放状态,比如什么时候音频加载完,正在播放的音频需要有个提示等等,为此我做了一组html+css,如下。

<div class="voice-list">
    <div class="voice">
        <div class="control">
            <a href="javascript:;" id="voicePlay" class="play"></a>
        </div>
        <div class="box">
            <div class="tip">
                <strong>
                    李白送汪伦
                </strong>
                <span id="voiceTip">loading</span>
            </div>
        </div>
    </div>
</div>

每个div.voice代表一条音频,其中div.control表示对此音频的控制,播放或暂停,而div.tip中含有此音频的标题及所处状态(加载中、播放中、已暂停和已经停止)

当然 Howler 已经提供了响应的方法,接下来扩展下

var sound = new Howl({
    src: ['/uploads/a.mp3'],
    html5: true,
    onload:function(){
        $('#voiceTip').html("音频已加载");
    },
    onplay:function(){
        $('#voiceTip').html("播放中");
    },
    onpause:function(){
        $('#voiceTip').html("暂停");
    },
    onend: function() {
        $('#voiceTip').html("播放结束");
    }
});

sound.play();// 开始播放

我们插入了4个函数,代表此音频进入的几种状态,Howler在行为上提供了比如.play()、.pause()、.stop()等来实现音频的播放等功能,于此同时也提供了响应的on函数来进行监听,比如上面的onload表示音频加载完成,比如onplay表示当前执行了play()播放方法。。。。

等等等等,具体可以查看 Howler 的readme,传送门

看看上面代码的效果图

当然上面的代码不是我们想要的,它自动播放,我们希望用户点击了播放按钮(div.control)后进行播放或暂停,这需要解决两个问题

  1. 必须是音频加载完成后才能播放。
  2. 根据当前音频的状态来确定点击后是播放还是暂停。

也就是说我们需要在点击播放按钮那一刻知道当前音频的状态,Howl 提供了一个 state()方法,用来获取当前此音频在什么状态(unloaded、loading 或 loaded)。

为此我是这样计划的

  1. 去掉自动播放功能
  2. 为播放按钮(div.control)绑定点击(click)事件
  3. 判断当前音频状态并给与对于的策略

于是有了下面的代码

var sound = new Howl({
    src: ['/uploads/a.mp3'],
    html5: true,
    onload:function(){
        $('#voiceTip').html("音频已加载");
    },
    onplay:function(){
        $('#voiceTip').html("播放中");
        $('#voicePlay').addClass('playing');
    },
    onpause:function(){
        $('#voiceTip').html("暂停");
        $('#voicePlay').removeClass('playing');
    },
    onend: function() {
        $('#voiceTip').html("播放结束");
        $('#voicePlay').removeClass('playing');
    }
});

$('#voicePlay').click(function(){
    if(sound.state() === 'loading' || sound.state() === 'unloaded'){
        weui.alert('音频加载中,请稍后播放。');
        return false;
    }else if(sound.state() === 'loaded'){
        if($(this).hasClass('playing')){
            sound.pause();
        }else{
            sound.play();
        }
    }
});

去掉自动播放功能很简单,只需要不写入sound.play()即可。

然后我们通过 $('#voicePlay').click(fnction()) 实现了对按钮点击的监听,此时使用 sound.state() 来获取当前视频的状态。

要注意,此方法返回值当处于 loaded 时音频仍可能处于两个状态(播放或暂停),因此我们人工为 控制按钮div.controll 增加了一个类 playing,当 playing 类存在的时候表示当前音频处于播放状态,则要执行暂停,否则执行播放。

增加一个 playing 的另一个好处是我们可以控制按钮的样式(播放或暂停),增强用户体验。

重点 我想你注意到了,对于 playing 的添加和删除我们放到了监听函数中,这是因为每一个音频行为都会触发对应的监听函数,比如play()方法会触发onplay监听函数。

万里长城走完了一半,继续。

SiriWave 高逼格的波纹

上面我们说了,当音频处于播放状态时,我们可以让控制按钮变成一个gif小动画,比如下面

但是我希望它更帅气一点,因此我引入了 SiriWave 库(github

看效果,我想你会喜欢。

<div class="voice-list">
    <div class="voice">
        <div class="control">
            <a href="javascript:;" id="voicePlay" class="play"></a>
        </div>
        <div class="box">
            <div class="tip">
                <strong>
                    李白送汪伦
                </strong>
                <span id="voiceTip">loading</span>
            </div>
            <div id="line"></div>
        </div>
    </div>
</div>

使用方法也很简单,建立一个容器(div.line),将波形放进去。

var wave = new SiriWave({
    container: document.getElementById("line"),
    width: window.innerWidth,
    height:50,
    color:'#1dcc0f',
    cover: true,
    speed: 0.03,
    amplitude: 0.7,
    frequency: 2
});

当然上面只是建立了波形对象,什么时候启动/停止要使用SiriWave的start()/stop()方法,我们要跟音频同步,因此进行一次大整合,如下代码。

var wave = new SiriWave({
    container: document.getElementById("line"),
    width: window.innerWidth,
    height:50,
    color:'#1dcc0f',
    cover: true,
    speed: 0.03,
    amplitude: 0.7,
    frequency: 2
});

var sound = new Howl({
    src: ['/uploads/a.mp3'],
    html5: true,
    onload:function(){
        $('#voiceTip').html("音频已加载");
    },
    onplay:function(){
        $('#voiceTip').html("播放中");
        $('#voicePlay').addClass('playing');
        wave.start();
    },
    onpause:function(){
        $('#voiceTip').html("暂停");
        $('#voicePlay').removeClass('playing');
        wave.stop();
    },
    onend: function() {
        $('#voiceTip').html("播放结束");
        $('#voicePlay').removeClass('playing');
        wave.stop();
    }
});

$('#voicePlay').click(function(){
    if(sound.state() === 'loading' || sound.state() === 'unloaded'){
        weui.alert('音频加载中,请稍后播放。');
        return false;
    }else if(sound.state() === 'loaded'){
        if($(this).hasClass('playing')){
            sound.pause();
        }else{
            sound.play();
        }
    }
});

多音频播放

Howl其实是支持多视频播放的,比如如下代码

var sound = new Howl({
    src: ['/uploads/a.mp3','/uploads/b.mpg'],
    html5: true
});

sound.play();// 开始播放

我们可以为src传入一个数组,但是这个多视频播放是连续播放的概念,当a.mp3完成继续播放b.mp3。

而我们现在的需求是多个音频播放器,而不是连续的意思,那就需要使用数组来存放每个 Howl 对象。

var sounds = [];
var waves = [];

接下来会有一个遍历

<div class="voice-list">
    循环开始
    <div class="voice">
    <script type="text/javascript">
        sounds[音频ID] = new Howl({
            src: ['音频路径'],
        });
    </script>
    </div>
    循环结束
</div>

接下来我们的操作就是对某个数组项即可

sounds[xxx].play(); 

小结

实现音频播放的方法有很多,这里仅抛砖引玉,如果你有好的思路或开源库,请留言赐教。

322 浏览 5 收藏 报告 阅读模式
载入中...