小程序音频播放器及进度条Taro

起初,音频肯定是先想到InnerAudioContext,但因为项目需要嵌套在腾讯随行app里面,所以这里需要调用的是背景音频getBackgroundAudioManager,思路是差不多的。

const audioContext = Taro.getBackgroundAudioManager();
let timer = null

interface IState {
  isAnimation: boolean;
  duration: number;
  audioCurrent: number;
  progressPrcent: number
}
export default class List extends Component<IProps, IState> {
  constructor(props: IProps | undefined) {
    super(props);
    this.state = {
      isAnimation: false,
      duration: 0,
      audioCurrent: 0,
      progressPrcent: 0
    };
  }
  componentWillUnmount() {
    wx.stopBackgroundAudio()
  }
  componentDidMount() {
	this.getScenicDetail()
  }

  getScenicDetail() {
    this.props.dispatch({
      type: 'home/getScenicDetail',
      payload: {
          scenicId: this.$router.params.id
      },
      callback: (info) => {
        this.setState({
          scenicInfo: info
        }, () => {
          this.initialization(info.voiceFile, info.name)
        })
      }
    })
  }

  //初始化播放器,获取duration
  initialization(src, name) {
    if (src) {
      const self = this;
      //设置src
      audioContext.src = src && (src.indexOf('https:') > -1 ? src : buildCdnPath(src))
      //运行一次
      audioContext.title = name;
      audioContext.play()
      // audioContext.pause() //因为需求是要求页面初始化就自动播放,所以这里没有执行pause
      audioContext.onPlay(() => {
        //开始播放事件
        timer = setTimeout(function() {
          //延时获取音频真正的duration
          console.log(audioContext.duration)
          // 这个判断是防止多个音频切换时,图标未显示暂停状态
          if (audioContext.duration === 0 || audioContext.duration === null) {
            self.setState({
              isAnimation: false
            });
          } else {
            self.setState({
              isAnimation: true,
              duration: audioContext.duration
            });
          }
        }, 500)
      });
      audioContext.onTimeUpdate(() => {
      // 这个if是防止为获取到时长时,图标显示的问题;如果不存在这bug,直接执行else里面的代码就行
        if (this.state.duration === null || this.state.duration === 0 ) {
          this.setState({
            progressPrcent: (audioContext.currentTime / audioContext.duration) * 100,
            audioCurrent:  audioContext.currentTime, 
            duration: audioContext.duration,
            isAnimation: audioContext.duration > 0
          });
        } else {
         this.setState({
           progressPrcent:
              (audioContext.currentTime / audioContext.duration) * 100,
            audioCurrent: audioContext.currentTime
          });
        }
      })
      audioContext.onEnded(() => {
        //自然播放结束事件
        this.setState({
          isAnimation: false,
          progressPrcent: 0,
          audioCurrent: 0,
          duration: this.state.duration
        });
      });

      //监听播放错误事件
      audioContext.onError(() => {
        // wx.stopBackgroundAudio() // 注意这里不需要暂停画蛇添足
        this.setState({
          isAnimation: false,
          progressPrcent: 0,
          audioCurrent: 0
        });
      });
    } else {
      // wx.stopBackgroundAudio() // 注意这里不需要暂停画蛇添足
      audioContext.pause()
      Taro.showToast({title: '该景点无语音播放地址', icon: 'none'})
      this.setState({
        isAnimation: false,
        duration: 0,
        progressPrcent: 0,
        audioCurrent: 0
      });
    }
  }

 // 播放和暂停
  playAudio(src, name) {
    if (!src) {
      Taro.showToast({title: '该景点无语音播放地址', icon: 'none'})
      return
    }
    if (!this.state.isAnimation) {
      this.setState({
        isAnimation: true
      })
      if (audioContext.duration === 0) {
        audioContext.src = src && (src.indexOf('https:') > -1 ? src : buildCdnPath(src))
        audioContext.title = name
      }
      if (this.state.progressPrcent !== 0) {
      audioContext.seek((this.state.progressPrcent / 100) * this.state.duration);
      }
      audioContext.play()

    } else {
      audioContext.pause()
      this.setState({
        isAnimation: false
      });
    }
  }

 // 音频进度条拖放
  hanleSliderChange(e) {
    const position = e.detail.value
    const currentTime = (position / 100) * this.state.duration
    audioContext.seek(currentTime)
    audioContext.play()
    this.setState({
      progressPrcent: position,
      audioCurrent: currentTime
    })
  }

  // 切换音频景点
  toTabScenicInfo(info, index) {
  // 这里切换音频时注意不需要再执行暂停事件了,因为重新初始化音频地址和name时会自动暂停上一个音频
   this.setState({
      isAnimation: false,
      progressPrcent: 0,
      audioCurrent: 0,
      scenicInfo: info
    }, () => {
      this.initialization(info && info.voiceFile, info && info.name)
    })
  }

  // 音频时间格式化
  format(t) {
    let time =
      Math.floor(t / 60) >= 10 ? Math.floor(t / 60) : "0" + Math.floor(t / 60);
    t = time + ":" + ((t % 60) / 100).toFixed(2).slice(-2);
    return t;
  }
  
  render() {
    const recordList = this.props.subScenic.list
    const { isAnimation, duration, audioCurrent, progressPrcent, scenicInfo } = this.state;
    const list = ((recordList && recordList.records) || []).map((item, index) => {
      return (
        <View className="list-item-wrap" key={String(index)}>
          <View
            className={listActive === item.subScenicId ? 'list-item active' : 'list-item'}
            onClick={this.toTabScenicInfo.bind(this, item, index)}
          >
            {
              index > 2 && <View className="vips">
                <View className="ribbon">VIP</View>
              </View>
            }
            {item.name}
          </View>
        </View>
      );
    });

    return (
     	<View className="audios">
	        <View className="img-audio">
	           {!isAnimation ? (
	               <Image
	                   className="audio_btn"
	                   src={icon_stop}
	                   onClick={this.playAudio.bind(
	                       this, scenicInfo.voiceFile, scenicInfo.name
	                   )}
	               />
	           ) : (
	               <Image
	                   className="audio_btn"
	                   src={icon_play}
	                   onClick={this.playAudio.bind(
	                       this, scenicInfo.voiceFile, scenicInfo.name
	                   )}
	               />
	           )}
	           <View>语音解说</View>
	         </View>
	         <View className="progerss-con">
	             <Text className="left_text">{this.format(audioCurrent)}</Text>
	             <Slider
	                 class="mp-slider-bar"
	                 block-size="16"
	                 value={progressPrcent}
	                 activeColor="#e3c703"
	                 className="progress-bar"
	                 disabled={!scenicInfo.voiceFile}
	                 onChange={this.hanleSliderChange.bind(this)}
	             />
	             <Text className="right_text">{this.format(duration)}</Text>
	          </View>
	    </View>
    );
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值