audio.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /**
  2. * @fileoverview audio 组件
  3. */
  4. const context = require('./context')
  5. Component({
  6. data: {
  7. time: '00:00'
  8. },
  9. properties: {
  10. name: String, // 音乐名
  11. author: String, // 作者
  12. poster: String, // 海报图片地址
  13. autoplay: Boolean, // 是否自动播放
  14. controls: Boolean, // 是否显示控件
  15. loop: Boolean, // 是否循环播放
  16. src: { // 源地址
  17. type: String,
  18. observer (src) {
  19. this.setSrc(src)
  20. }
  21. }
  22. },
  23. created () {
  24. // 创建内部 context
  25. this._ctx = wx.createInnerAudioContext()
  26. this._ctx.onError(err => {
  27. this.setData({
  28. error: true
  29. })
  30. this.triggerEvent('error', err)
  31. })
  32. this._ctx.onTimeUpdate(() => {
  33. const time = this._ctx.currentTime
  34. const min = parseInt(time / 60)
  35. const sec = Math.ceil(time % 60)
  36. const data = {}
  37. data.time = (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
  38. // 不在拖动状态下需要更新进度条
  39. if (!this.lastTime) {
  40. data.value = time / this._ctx.duration * 100
  41. }
  42. this.setData(data)
  43. })
  44. this._ctx.onEnded(() => {
  45. if (!this.properties.loop) {
  46. this.setData({
  47. playing: false
  48. })
  49. }
  50. })
  51. // #ifndef ALIPAY
  52. },
  53. attached () {
  54. context.set(this.id, this)
  55. // #endif
  56. // #ifdef MP-ALIPAY
  57. context.set(this.properties.id, this)
  58. this.setSrc(this.properties.src)
  59. // #endif
  60. },
  61. // #ifdef MP-ALIPAY
  62. didUpdate (e) {
  63. if (e.src !== this.properties.src) {
  64. this.setSrc(this.properties.src)
  65. }
  66. },
  67. // #endif
  68. detached () {
  69. this._ctx.destroy()
  70. // #ifndef MP-ALIPAY
  71. context.remove(this.id)
  72. // #endif
  73. // #ifdef MP_ALIPAY
  74. context.remove(this.properties.id)
  75. // #endif
  76. },
  77. // #ifndef ALIPAY | TOUTIAO
  78. pageLifetimes: {
  79. show () {
  80. // 播放被后台打断时,页面显示后自动继续播放
  81. if (this.data.playing && this._ctx.paused) {
  82. this._ctx.play()
  83. }
  84. }
  85. },
  86. // #endif
  87. methods: {
  88. /**
  89. * @description 设置源
  90. * @param {string} src 源地址
  91. */
  92. setSrc (src) {
  93. this._ctx.autoplay = this.properties.autoplay
  94. this._ctx.loop = this.properties.loop
  95. this._ctx.src = src
  96. if (this.properties.autoplay && !this.data.playing) {
  97. this.setData({
  98. playing: true
  99. })
  100. }
  101. },
  102. /**
  103. * @description 播放音乐
  104. */
  105. play () {
  106. this._ctx.play()
  107. this.setData({
  108. playing: true
  109. })
  110. this.triggerEvent('play'
  111. // #ifdef MP-ALIPAY
  112. , {
  113. target: {
  114. id: this.props.id
  115. }
  116. }
  117. // #endif
  118. )
  119. },
  120. /**
  121. * @description 暂停音乐
  122. */
  123. pause () {
  124. this._ctx.pause()
  125. this.setData({
  126. playing: false
  127. })
  128. this.triggerEvent('pause')
  129. },
  130. /**
  131. * @description 设置播放速率
  132. * @param {Number} rate 播放速率
  133. */
  134. playbackRate (rate) {
  135. this._ctx.playbackRate = rate
  136. },
  137. /**
  138. * @description 停止音乐
  139. */
  140. stop () {
  141. this._ctx.stop()
  142. this.setData({
  143. playing: false,
  144. time: '00:00'
  145. })
  146. this.triggerEvent('stop')
  147. },
  148. /**
  149. * @description 控制进度
  150. * @param {number} sec 秒数
  151. */
  152. seek (sec) {
  153. this._ctx.seek(sec)
  154. },
  155. /**
  156. * @description 移动进度条
  157. * @param {event} e
  158. * @private
  159. */
  160. _seeking (e) {
  161. // 避免过于频繁 setData
  162. if (e.timeStamp - this.lastTime < 200) return
  163. const time = Math.round(e.detail.value / 100 * this._ctx.duration)
  164. const min = parseInt(time / 60)
  165. const sec = time % 60
  166. this.setData({
  167. time: (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
  168. })
  169. this.lastTime = e.timeStamp
  170. },
  171. /**
  172. * @description 进度条移动完毕
  173. * @param {event} e
  174. * @private
  175. */
  176. _seeked (e) {
  177. this._ctx.seek(e.detail.value / 100 * this._ctx.duration)
  178. this.lastTime = undefined
  179. }
  180. }
  181. })