最近做活动的时候,有个活动是展示目前排行前几名的歌手,并且可以点击听歌 。 可以发现每个列表只有一个按钮,但是一共有四种状态。 1. 默认状态,点击播放 2. 点击播放后,首先加载资源的加载中 3. 加载完成后的自动播放状态 4. 播放中再次点击的暂停状态 常规开发的时候应该是这么写的 ``` if (state === 'default') { loadingStuff() } else if (state === 'loading') { play(); } else if (state === 'playing') { pause(); } else if (state === 'pause') { play(); } ``` 我们会发现这个会有很多的`if`,`else`,分支越多,要维护的条件就越多。会导致代码变的很长难以阅读。所以当我们遇到这种大量分支语句的时候,可以考虑使用设计模式来删减分支数,毕竟代码是写给人看的。像这种单个按钮会有多种装态,就特别适合用状态模式来进行重构。 首先我们创建一个创建基类,每一个状态都抽象成一个class,让所有的状态类都继承这个基类  其实基类的作用主要是为了提醒开发者在创建状态类时不要忘记重写next方法,因为按钮被点击的本质,就是调用当前状态的`next`方法。 然后我们创建四个状态类     我们可以看到,每一个状态类的next方法,都指向它的下一个状态。可是仅仅只有四种类是不够的,我们需要创建一个来将它们放在一起进行统一管理的class来进行操作。这个class也必须包含`next`方法中我们没有生命的setState方法  至此我们已经基本完成了状态的管理。在调用中直接初始化即可,点击按钮调用当前实例的`next`方法  可以看到我们的主要逻辑没有了之前的分支,而且就算我们再继续增加状态。也只需要新增一个状态类,并将它的next指向正确的状态即可。 接下来讲一下audio播放的原理  audio的加载总共有这么几个过程。 1. 首先是调用`audio.load()`方法,加载音频文件 2. audio的事件`loadstart`触发,代表加载开始,切换状态到**加载中** 3. audio的事件`canplaythrough`触发,代表音频可以开始播放(但不一定加载完成)。此时可以直接调用`audio.play()`方法来播放音频了。 4. audio的事件`ended`代表播放结束。 5. `error`代表出错了。抛错即可 > ios手机有一个很坑的点,如果你不给<audio></audio>标签加上**autoplay**属性的话。即使你调用了audio.load()方法, safari依旧不会完全加载这个音频文件,而是只加载一部分(抓包可以看到请求是206部分加载。),如果这一部分还没有到能播放的程度,那么**canplaythrough**就无法触发。音频就无法一直播放
最近做活动的时候,有个活动是展示目前排行前几名的歌手,并且可以点击听歌
。
可以发现每个列表只有一个按钮,但是一共有四种状态。
常规开发的时候应该是这么写的
我们会发现这个会有很多的








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