190 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			190 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @fileoverview audio 组件
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const context = require('./context')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Component({
							 | 
						||
| 
								 | 
							
								  data: {
							 | 
						||
| 
								 | 
							
								    time: '00:00'
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  properties: {
							 | 
						||
| 
								 | 
							
								    name: String, // 音乐名
							 | 
						||
| 
								 | 
							
								    author: String, // 作者
							 | 
						||
| 
								 | 
							
								    poster: String, // 海报图片地址
							 | 
						||
| 
								 | 
							
								    autoplay: Boolean, // 是否自动播放
							 | 
						||
| 
								 | 
							
								    controls: Boolean, // 是否显示控件
							 | 
						||
| 
								 | 
							
								    loop: Boolean, // 是否循环播放
							 | 
						||
| 
								 | 
							
								    src: { // 源地址
							 | 
						||
| 
								 | 
							
								      type: String,
							 | 
						||
| 
								 | 
							
								      observer (src) {
							 | 
						||
| 
								 | 
							
								        this.setSrc(src)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  created () {
							 | 
						||
| 
								 | 
							
								    // 创建内部 context
							 | 
						||
| 
								 | 
							
								    this._ctx = wx.createInnerAudioContext()
							 | 
						||
| 
								 | 
							
								    this._ctx.onError(err => {
							 | 
						||
| 
								 | 
							
								      this.setData({
							 | 
						||
| 
								 | 
							
								        error: true
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      this.triggerEvent('error', err)
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    this._ctx.onTimeUpdate(() => {
							 | 
						||
| 
								 | 
							
								      const time = this._ctx.currentTime
							 | 
						||
| 
								 | 
							
								      const min = parseInt(time / 60)
							 | 
						||
| 
								 | 
							
								      const sec = Math.ceil(time % 60)
							 | 
						||
| 
								 | 
							
								      const data = {}
							 | 
						||
| 
								 | 
							
								      data.time = (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
							 | 
						||
| 
								 | 
							
								      // 不在拖动状态下需要更新进度条
							 | 
						||
| 
								 | 
							
								      if (!this.lastTime) {
							 | 
						||
| 
								 | 
							
								        data.value = time / this._ctx.duration * 100
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      this.setData(data)
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    this._ctx.onEnded(() => {
							 | 
						||
| 
								 | 
							
								      if (!this.properties.loop) {
							 | 
						||
| 
								 | 
							
								        this.setData({
							 | 
						||
| 
								 | 
							
								          playing: false
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    // #ifndef ALIPAY
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  attached () {
							 | 
						||
| 
								 | 
							
								    context.set(this.id, this)
							 | 
						||
| 
								 | 
							
								    // #endif
							 | 
						||
| 
								 | 
							
								    // #ifdef MP-ALIPAY
							 | 
						||
| 
								 | 
							
								    context.set(this.properties.id, this)
							 | 
						||
| 
								 | 
							
								    this.setSrc(this.properties.src)
							 | 
						||
| 
								 | 
							
								    // #endif
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  // #ifdef MP-ALIPAY
							 | 
						||
| 
								 | 
							
								  didUpdate (e) {
							 | 
						||
| 
								 | 
							
								    if (e.src !== this.properties.src) {
							 | 
						||
| 
								 | 
							
								      this.setSrc(this.properties.src)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  // #endif
							 | 
						||
| 
								 | 
							
								  detached () {
							 | 
						||
| 
								 | 
							
								    this._ctx.destroy()
							 | 
						||
| 
								 | 
							
								    // #ifndef MP-ALIPAY
							 | 
						||
| 
								 | 
							
								    context.remove(this.id)
							 | 
						||
| 
								 | 
							
								    // #endif
							 | 
						||
| 
								 | 
							
								    // #ifdef MP_ALIPAY
							 | 
						||
| 
								 | 
							
								    context.remove(this.properties.id)
							 | 
						||
| 
								 | 
							
								    // #endif
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  // #ifndef ALIPAY | TOUTIAO
							 | 
						||
| 
								 | 
							
								  pageLifetimes: {
							 | 
						||
| 
								 | 
							
								    show () {
							 | 
						||
| 
								 | 
							
								      // 播放被后台打断时,页面显示后自动继续播放
							 | 
						||
| 
								 | 
							
								      if (this.data.playing && this._ctx.paused) {
							 | 
						||
| 
								 | 
							
								        this._ctx.play()
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  },
							 | 
						||
| 
								 | 
							
								  // #endif
							 | 
						||
| 
								 | 
							
								  methods: {
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 设置源
							 | 
						||
| 
								 | 
							
								     * @param {string} src 源地址
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    setSrc (src) {
							 | 
						||
| 
								 | 
							
								      this._ctx.autoplay = this.properties.autoplay
							 | 
						||
| 
								 | 
							
								      this._ctx.loop = this.properties.loop
							 | 
						||
| 
								 | 
							
								      this._ctx.src = src
							 | 
						||
| 
								 | 
							
								      if (this.properties.autoplay && !this.data.playing) {
							 | 
						||
| 
								 | 
							
								        this.setData({
							 | 
						||
| 
								 | 
							
								          playing: true
							 | 
						||
| 
								 | 
							
								        })
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 播放音乐
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    play () {
							 | 
						||
| 
								 | 
							
								      this._ctx.play()
							 | 
						||
| 
								 | 
							
								      this.setData({
							 | 
						||
| 
								 | 
							
								        playing: true
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      this.triggerEvent('play'
							 | 
						||
| 
								 | 
							
								        // #ifdef MP-ALIPAY
							 | 
						||
| 
								 | 
							
								        , {
							 | 
						||
| 
								 | 
							
								          target: {
							 | 
						||
| 
								 | 
							
								            id: this.props.id
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        // #endif
							 | 
						||
| 
								 | 
							
								      )
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 暂停音乐
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    pause () {
							 | 
						||
| 
								 | 
							
								      this._ctx.pause()
							 | 
						||
| 
								 | 
							
								      this.setData({
							 | 
						||
| 
								 | 
							
								        playing: false
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      this.triggerEvent('pause')
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 设置播放速率
							 | 
						||
| 
								 | 
							
								     * @param {Number} rate 播放速率
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    playbackRate (rate) {
							 | 
						||
| 
								 | 
							
								      this._ctx.playbackRate = rate
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 停止音乐
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    stop () {
							 | 
						||
| 
								 | 
							
								      this._ctx.stop()
							 | 
						||
| 
								 | 
							
								      this.setData({
							 | 
						||
| 
								 | 
							
								        playing: false,
							 | 
						||
| 
								 | 
							
								        time: '00:00'
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      this.triggerEvent('stop')
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 控制进度
							 | 
						||
| 
								 | 
							
								     * @param {number} sec 秒数
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    seek (sec) {
							 | 
						||
| 
								 | 
							
								      this._ctx.seek(sec)
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 移动进度条
							 | 
						||
| 
								 | 
							
								     * @param {event} e
							 | 
						||
| 
								 | 
							
								     * @private
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    _seeking (e) {
							 | 
						||
| 
								 | 
							
								      // 避免过于频繁 setData
							 | 
						||
| 
								 | 
							
								      if (e.timeStamp - this.lastTime < 200) return
							 | 
						||
| 
								 | 
							
								      const time = Math.round(e.detail.value / 100 * this._ctx.duration)
							 | 
						||
| 
								 | 
							
								      const min = parseInt(time / 60)
							 | 
						||
| 
								 | 
							
								      const sec = time % 60
							 | 
						||
| 
								 | 
							
								      this.setData({
							 | 
						||
| 
								 | 
							
								        time: (min > 9 ? min : '0' + min) + ':' + (sec > 9 ? sec : '0' + sec)
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								      this.lastTime = e.timeStamp
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    /**
							 | 
						||
| 
								 | 
							
								     * @description 进度条移动完毕
							 | 
						||
| 
								 | 
							
								     * @param {event} e
							 | 
						||
| 
								 | 
							
								     * @private
							 | 
						||
| 
								 | 
							
								     */
							 | 
						||
| 
								 | 
							
								    _seeked (e) {
							 | 
						||
| 
								 | 
							
								      this._ctx.seek(e.detail.value / 100 * this._ctx.duration)
							 | 
						||
| 
								 | 
							
								      this.lastTime = undefined
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								})
							 |