audio.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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. context.remove(this.properties.audioId)
  71. },
  72. // #ifndef ALIPAY | TOUTIAO
  73. pageLifetimes: {
  74. show () {
  75. // 播放被后台打断时,页面显示后自动继续播放
  76. if (this.data.playing && this._ctx.paused) {
  77. this._ctx.play()
  78. }
  79. }
  80. },
  81. // #endif
  82. methods: {
  83. /**
  84. * @description 设置源
  85. * @param {string} src 源地址
  86. */
  87. setSrc (src) {
  88. this._ctx.autoplay = this.properties.autoplay
  89. this._ctx.loop = this.properties.loop
  90. this._ctx.src = src
  91. if (this.properties.autoplay && !this.data.playing) {
  92. this.setData({
  93. playing: true
  94. })
  95. }
  96. },
  97. /**
  98. * @description 播放音乐
  99. */
  100. play () {
  101. this._ctx.play()
  102. this.setData({
  103. playing: true
  104. })
  105. this.triggerEvent('play'
  106. // #ifdef MP-ALIPAY
  107. , {
  108. target: {
  109. id: this.props.id
  110. }
  111. }
  112. // #endif
  113. )
  114. },
  115. /**
  116. * @description 暂停音乐
  117. */
  118. pause () {
  119. this._ctx.pause()
  120. this.setData({
  121. playing: false
  122. })
  123. this.triggerEvent('pause')
  124. },
  125. /**
  126. * @description 停止音乐
  127. */
  128. stop () {
  129. this._ctx.stop()
  130. this.setData({
  131. playing: false,
  132. time: '00:00'
  133. })
  134. this.triggerEvent('stop')
  135. },
  136. /**
  137. * @description 控制进度
  138. * @param {number} sec 秒数
  139. */
  140. seek (sec) {
  141. this._ctx.seek(sec)
  142. },
  143. /**
  144. * @description 移动进度条
  145. * @param {event} e
  146. * @private
  147. */
  148. _seeking (e) {
  149. // 避免过于频繁 setData
  150. if (e.timeStamp - this.lastTime < 200) return
  151. const time = Math.round(e.detail.value / 100 * this._ctx.duration)
  152. const min = parseInt(time / 60)
  153. const sec = time % 60
  154. this.setData({
  155. time: (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
  156. })
  157. this.lastTime = e.timeStamp
  158. },
  159. /**
  160. * @description 进度条移动完毕
  161. * @param {event} e
  162. * @private
  163. */
  164. _seeked (e) {
  165. this._ctx.seek(e.detail.value / 100 * this._ctx.duration)
  166. this.lastTime = undefined
  167. }
  168. }
  169. })