audio.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. enum PlayStatus {
  2. none,
  3. playBefore,
  4. play,
  5. playFail,
  6. pause
  7. }
  8. enum TriggerAudioListener {
  9. fail='fail',
  10. canplay='canplay',
  11. ended='ended',
  12. speed='speed',
  13. status='status'
  14. }
  15. class CustomAudio {
  16. audio:HTMLAudioElement = undefined;
  17. src:string = '';
  18. triggers:Record<string, any>={};
  19. status:PlayStatus = PlayStatus.none
  20. // 设置播放路径
  21. setSrc(src:string){
  22. if (!CustomAudio.supper) return;
  23. if (src && src !== this.src) {
  24. // 清空所有监听事件
  25. this.triggers = {};
  26. this.src = src;
  27. this.status = PlayStatus.none;
  28. if (this.audio === undefined) {
  29. this.audio = document.createElement('audio');
  30. this.audio.setAttribute('style','display:none');
  31. this.audio.src = src;
  32. // 播放结束
  33. this.audio.addEventListener('ended', ()=> {
  34. this.setStatus(PlayStatus.pause);
  35. return this.triggerListener(TriggerAudioListener.canplay,{
  36. duration: this.getDuration(this.audio.duration)
  37. });
  38. }, false);
  39. // 加载就绪
  40. this.audio.addEventListener('canplay', ()=> {
  41. return this.triggerListener(TriggerAudioListener.canplay,{
  42. duration: this.getDuration(this.audio.duration)
  43. });
  44. }, false);
  45. // 加载失败
  46. this.audio.addEventListener('error', ()=> {
  47. return this.triggerListener(TriggerAudioListener.fail,{
  48. message:'加载失败'
  49. });
  50. }, false);
  51. document.body.appendChild(this.audio);
  52. } else {
  53. this.audio.src = src;
  54. }
  55. }
  56. return this;
  57. }
  58. getDuration(duration:number){
  59. duration = parseFloat(duration.toFixed(2));
  60. return Math.floor(duration);
  61. }
  62. // 播放
  63. play(){
  64. if (!this.audio || this.status === PlayStatus.play || this.status === PlayStatus.playBefore) return;
  65. this.setStatus(PlayStatus.playBefore);
  66. this.audio.play().then(()=>{
  67. this.setStatus(PlayStatus.play);
  68. }).catch(()=>{
  69. this.setStatus(PlayStatus.playFail);
  70. });
  71. return this;
  72. }
  73. private triggerTime;
  74. triggerSpeed(){
  75. clearTimeout(this.triggerTime);
  76. let params = {
  77. duration: this.getDuration(this.audio.duration),
  78. currDuration: this.getDuration(this.audio.currentTime)
  79. };
  80. let diff = this.audio.duration - this.audio.currentTime;
  81. this.triggerListener(TriggerAudioListener.speed,params);
  82. if (diff > 0) {
  83. this.triggerTime = setTimeout(()=> this.triggerSpeed(),1000);
  84. } else {
  85. return ;
  86. }
  87. }
  88. // 暂停
  89. paused(){
  90. if (!this.audio || this.status === PlayStatus.pause) return;
  91. this.setStatus(PlayStatus.pause);
  92. this.audio.pause();
  93. return this;
  94. }
  95. setStatus(status:PlayStatus){
  96. if (this.status !== status) {
  97. this.status = status;
  98. if (status === PlayStatus.play) {
  99. this.triggerSpeed();
  100. } else {
  101. clearTimeout(this.triggerTime);
  102. }
  103. return this.triggerListener(TriggerAudioListener.status,status);
  104. }
  105. }
  106. addListener(key:TriggerAudioListener,callback:Function) {
  107. if (!callback) return;
  108. if (this.triggers[key] === undefined) this.triggers[key] = [callback];
  109. else this.triggers[key].push(callback);
  110. return this;
  111. }
  112. removeListener(key:TriggerAudioListener,callback:Function) {
  113. if (!callback || this.triggers[key] === undefined) return;
  114. let index = this.triggers[key].indexOf(callback);
  115. if (index>=0) this.triggers[key].splice(index,1);
  116. return this;
  117. }
  118. triggerListener(key:TriggerAudioListener,data?:any) {
  119. if (this.triggers[key]) {
  120. this.triggers[key].map((item)=> item && item(data));
  121. }
  122. }
  123. static supper:boolean = !!(document.createElement('audio').canPlayType)
  124. }
  125. export {CustomAudio,TriggerAudioListener,PlayStatus};
  126. export default new CustomAudio();