Skip to content

使用状态模式开发一个播放列表 #20

@EmberYu

Description

@EmberYu

最近做活动的时候,有个活动是展示目前排行前几名的歌手,并且可以点击听歌
image
可以发现每个列表只有一个按钮,但是一共有四种状态。

  1. 默认状态,点击播放
  2. 点击播放后,首先加载资源的加载中
  3. 加载完成后的自动播放状态
  4. 播放中再次点击的暂停状态
    常规开发的时候应该是这么写的
if (state === 'default') {
  loadingStuff()
} else if (state === 'loading') {
  play();
} else if (state === 'playing') {
  pause();
} else if (state === 'pause') {
  play();
}

我们会发现这个会有很多的ifelse,分支越多,要维护的条件就越多。会导致代码变的很长难以阅读。所以当我们遇到这种大量分支语句的时候,可以考虑使用设计模式来删减分支数,毕竟代码是写给人看的。像这种单个按钮会有多种装态,就特别适合用状态模式来进行重构。
首先我们创建一个创建基类,每一个状态都抽象成一个class,让所有的状态类都继承这个基类
image
其实基类的作用主要是为了提醒开发者在创建状态类时不要忘记重写next方法,因为按钮被点击的本质,就是调用当前状态的next方法。
然后我们创建四个状态类
image
image
image
image
我们可以看到,每一个状态类的next方法,都指向它的下一个状态。可是仅仅只有四种类是不够的,我们需要创建一个来将它们放在一起进行统一管理的class来进行操作。这个class也必须包含next方法中我们没有生命的setState方法
image
至此我们已经基本完成了状态的管理。在调用中直接初始化即可,点击按钮调用当前实例的next方法
image
可以看到我们的主要逻辑没有了之前的分支,而且就算我们再继续增加状态。也只需要新增一个状态类,并将它的next指向正确的状态即可。
接下来讲一下audio播放的原理
image
audio的加载总共有这么几个过程。

  1. 首先是调用audio.load()方法,加载音频文件
  2. audio的事件loadstart触发,代表加载开始,切换状态到加载中
  3. audio的事件canplaythrough触发,代表音频可以开始播放(但不一定加载完成)。此时可以直接调用audio.play()方法来播放音频了。
  4. audio的事件ended代表播放结束。
  5. error代表出错了。抛错即可

ios手机有一个很坑的点,如果你不给标签加上autoplay属性的话。即使你调用了audio.load()方法, safari依旧不会完全加载这个音频文件,而是只加载一部分(抓包可以看到请求是206部分加载。),如果这一部分还没有到能播放的程度,那么canplaythrough就无法触发。音频就无法一直播放

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions