|
|
@@ -0,0 +1,402 @@
|
|
|
+<template>
|
|
|
+ <view class="audio_container">
|
|
|
+ <view class="title-box">
|
|
|
+ {{ title }}
|
|
|
+ </view>
|
|
|
+ <view>
|
|
|
+ <slider :backgroundColor='backgroundColor' :activeColor='activeColor' @change="handleSliderChange"
|
|
|
+ :value="sliderIndex" :max="maxSliderIndex" block-color="#C30D23" block-size="16" />
|
|
|
+ </view>
|
|
|
+ <view style="padding: 0px 7.5px 0px 7.5px ; display: block; ">
|
|
|
+ <view style="float: left; font-size: 10px;color:#848484;">
|
|
|
+ {{ currentTimeText }}
|
|
|
+ </view>
|
|
|
+ <view style="float: right;font-size: 10px;color:#848484;">
|
|
|
+ {{ totalTimeText }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view style="margin-top: 35px;">
|
|
|
+ <view class="control">
|
|
|
+ <view class="uni-grid-icon">
|
|
|
+ <image @tap="handleFastRewind" src="../static/images/get-back.svg"
|
|
|
+ style="width: 24px;height: 24px;top:3px;">
|
|
|
+ </image>
|
|
|
+ </view>
|
|
|
+ <view class="uni-grid-icon">
|
|
|
+ <image @tap="handleChangeAudioState" v-show="!isPlaying" src="../static/images/play.svg"
|
|
|
+ style="width: 24px;height: 24px;top:3px;">
|
|
|
+ </image>
|
|
|
+ <image @tap="handleChangeAudioState" v-show="isPlaying" src="../static/images/pause.svg"
|
|
|
+ style="width: 24px;height: 24px;top:3px;">
|
|
|
+ </image>
|
|
|
+ </view>
|
|
|
+ <view class="uni-grid-icon">
|
|
|
+ <image @tap="handleFastForward" src="../static/images/fast-forward.svg"
|
|
|
+ style="width: 24px;height: 24px;top:3px;">
|
|
|
+ </image>
|
|
|
+ </view>
|
|
|
+ <!-- <view class="uni-grid-icon">
|
|
|
+ <image @tap="handleLoopPlay" src="../static/images/Loop.svg"
|
|
|
+ style="width: 24px;height: 24px; top:3px; ">
|
|
|
+ </image>
|
|
|
+ </view> -->
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ name: 'my-audio',
|
|
|
+ //audioPlay开始播放
|
|
|
+ //audioPause停止播放
|
|
|
+ //audioEnd音频自然播放结束事件
|
|
|
+ //audioCanplay音频进入可以播放状态,但不保证后面可以流畅播放
|
|
|
+ //change播放状态改变 返回值false停止播放 true开始播放
|
|
|
+ //audioError 播放器错误
|
|
|
+ emits: ['audioPlay', 'audioPause', 'audioEnd', 'audioCanplay', 'change', 'audioError'],
|
|
|
+ props: {
|
|
|
+ title: {
|
|
|
+ type: String
|
|
|
+ },
|
|
|
+ //是否自动播放
|
|
|
+ autoplay: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ //滑块左侧已选择部分的线条颜色
|
|
|
+ activeColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#C30D23'
|
|
|
+ },
|
|
|
+ //滑块右侧背景条的颜色
|
|
|
+ backgroundColor: {
|
|
|
+ type: String,
|
|
|
+ default: '#E5E5E5'
|
|
|
+ },
|
|
|
+ //音频地址
|
|
|
+ src: {
|
|
|
+ type: [String, Array],
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ //是否倒计时
|
|
|
+ isCountDown: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ //音乐封面
|
|
|
+ audioCover: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ //是否显示收藏按钮
|
|
|
+ isCollectBtn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ //是否显示分享按钮
|
|
|
+ isShareBtn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ totalTimeText: '00:00', //视频总长度文字
|
|
|
+ currentTimeText: '00:00:00', //视频已播放长度文字
|
|
|
+
|
|
|
+ isPlaying: false, //播放状态
|
|
|
+
|
|
|
+ sliderIndex: 0, //滑块当前值
|
|
|
+ maxSliderIndex: 100, //滑块最大值
|
|
|
+
|
|
|
+ IsReadyPlay: false, //是否已经准备好可以播放了
|
|
|
+
|
|
|
+ isLoop: false, //是否循环播放
|
|
|
+
|
|
|
+ speedValue: [0.5, 0.8, 1.0, 1.25, 1.5, 2.0],
|
|
|
+ speedValueIndex: 2,
|
|
|
+ playSpeed: '1.0', //播放倍速 可取值:0.5/0.8/1.0/1.25/1.5/2.0
|
|
|
+
|
|
|
+ stringObject: (data) => {
|
|
|
+ return typeof (data)
|
|
|
+ },
|
|
|
+ innerAudioContext: uni.createInnerAudioContext()
|
|
|
+ }
|
|
|
+ },
|
|
|
+ async mounted() {
|
|
|
+ this.innerAudioContext.src = typeof (this.src) == 'string' ? this.src : this.src[0];
|
|
|
+ if (this.autoplay) {
|
|
|
+ if (!this.src) return console.error('src cannot be empty,The target value is string or array')
|
|
|
+
|
|
|
+ // #ifdef H5
|
|
|
+ var ua = window.navigator.userAgent.toLowerCase();
|
|
|
+ if (ua.match(/MicroMessenger/i) == 'micromessenger') {
|
|
|
+ const jweixin = require('../utils/jweixin');
|
|
|
+
|
|
|
+ jweixin.config({});
|
|
|
+ jweixin.ready(() => {
|
|
|
+ WeixinJSBridge.invoke('getNetworkType', {}, (e) => {
|
|
|
+ this.innerAudioContext.play();
|
|
|
+
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // #ifndef H5
|
|
|
+ this.innerAudioContext.autoplay = true;
|
|
|
+ // #endif
|
|
|
+ }
|
|
|
+
|
|
|
+ //音频播放事件
|
|
|
+ this.innerAudioContext.onPlay(() => {
|
|
|
+ this.isPlaying = true;
|
|
|
+ this.$emit('audioPlay')
|
|
|
+
|
|
|
+ this.$emit('change', {
|
|
|
+ state: true
|
|
|
+ });
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.maxSliderIndex = parseFloat(this.innerAudioContext.duration).toFixed(2);
|
|
|
+
|
|
|
+ }, 100)
|
|
|
+ });
|
|
|
+
|
|
|
+ //音频暂停事件
|
|
|
+ this.innerAudioContext.onPause(() => {
|
|
|
+ this.$emit('audioPause');
|
|
|
+ this.$emit('change', {
|
|
|
+ state: false
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ //音频自然播放结束事件
|
|
|
+ this.innerAudioContext.onEnded(() => {
|
|
|
+ this.isPlaying = !this.isPlaying;
|
|
|
+ this.$emit('audioEnd');
|
|
|
+
|
|
|
+ if (this.isLoop) {
|
|
|
+ this.changePlayProgress(0);
|
|
|
+ this.innerAudioContext.play();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ //音频进入可以播放状态,但不保证后面可以流畅播放
|
|
|
+ this.innerAudioContext.onCanplay((event) => {
|
|
|
+
|
|
|
+ this.IsReadyPlay = true;
|
|
|
+
|
|
|
+ this.$emit('audioCanplay');
|
|
|
+
|
|
|
+ let duration = this.innerAudioContext.duration;
|
|
|
+
|
|
|
+ //console.log('总时长', duration)
|
|
|
+
|
|
|
+ //将当前音频长度秒转换为00:00:00格式
|
|
|
+ this.totalTimeText = this.getFormateTime(duration);
|
|
|
+ this.maxSliderIndex = parseFloat(duration).toFixed(2);
|
|
|
+
|
|
|
+ //console.log(this.getFormateTime(duration))
|
|
|
+
|
|
|
+ //console.log('总时长1', this.totalTimeText)
|
|
|
+
|
|
|
+ //防止视频无法正确获取时长
|
|
|
+ setTimeout(() => {
|
|
|
+ duration = this.innerAudioContext.duration;
|
|
|
+
|
|
|
+ //将当前音频长度秒转换为00:00:00格式
|
|
|
+ this.totalTimeText = this.getFormateTime(duration);
|
|
|
+ this.maxSliderIndex = parseFloat(duration).toFixed(2);
|
|
|
+
|
|
|
+ //console.log('总时长2', this.totalTimeText)
|
|
|
+ }, 300)
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ //音频播放错误事件
|
|
|
+ this.innerAudioContext.onTimeUpdate((res) => {
|
|
|
+ this.sliderIndex = parseFloat(this.innerAudioContext.currentTime).toFixed(2);
|
|
|
+ this.currentTimeText = this.getFormateTime(this.innerAudioContext.currentTime);
|
|
|
+ });
|
|
|
+
|
|
|
+ //音频播放错误事件
|
|
|
+ this.innerAudioContext.onError((res) => {
|
|
|
+ console.log(res.errMsg);
|
|
|
+ console.log(res.errCode);
|
|
|
+ this.$emit('change', {
|
|
|
+ state: false
|
|
|
+ });
|
|
|
+ this.audioPause();
|
|
|
+
|
|
|
+ this.$emit('audioError', res);
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ //销毁innerAudioContext()实例
|
|
|
+ audioDestroy() {
|
|
|
+ if (this.innerAudioContext) {
|
|
|
+ this.innerAudioContext.destroy();
|
|
|
+ this.isPlaying = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //点击变更播放状态
|
|
|
+ handleChangeAudioState() {
|
|
|
+ if (this.isPlaying && !this.innerAudioContext.paused) {
|
|
|
+ this.audioPause();
|
|
|
+ } else {
|
|
|
+ this.audioPlay();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //开始播放
|
|
|
+ audioPlay() {
|
|
|
+ this.innerAudioContext.play();
|
|
|
+ this.isPlaying = true;
|
|
|
+ },
|
|
|
+ //暂停播放
|
|
|
+ audioPause() {
|
|
|
+ this.innerAudioContext.pause();
|
|
|
+ this.isPlaying = false;
|
|
|
+ },
|
|
|
+ //变更滑块位置
|
|
|
+ handleSliderChange(e) {
|
|
|
+ this.changePlayProgress(e.detail ? e.detail.value : e)
|
|
|
+ },
|
|
|
+ //更改播放倍速
|
|
|
+ handleChageSpeed() {
|
|
|
+ //获取播放倍速列表长度
|
|
|
+ let speedCount = this.speedValue.length;
|
|
|
+ //如果当前是最大倍速,从-1开始
|
|
|
+ if (this.speedValueIndex == (speedCount - 1)) {
|
|
|
+ this.speedValueIndex = -1;
|
|
|
+ }
|
|
|
+ //最新倍速序号
|
|
|
+ this.speedValueIndex += 1;
|
|
|
+ //获取最新倍速文字
|
|
|
+ this.playSpeed = this.speedValue[this.speedValueIndex].toFixed(1);
|
|
|
+ //暂停播放
|
|
|
+ this.audioPause();
|
|
|
+ //变更播放倍速
|
|
|
+ this.innerAudioContext.playbackRate(this.speedValue[this.speedValueIndex]);
|
|
|
+ //开始播放
|
|
|
+ this.audioPlay();
|
|
|
+ },
|
|
|
+ //快退15秒
|
|
|
+ handleFastRewind() {
|
|
|
+ if (this.IsReadyPlay) {
|
|
|
+ let value = parseInt(this.sliderIndex) - 15;
|
|
|
+ this.changePlayProgress(value >= 0 ? value : 0);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //快进15秒
|
|
|
+ handleFastForward() {
|
|
|
+ if (this.IsReadyPlay) {
|
|
|
+ let value = parseInt(this.sliderIndex) + 15;
|
|
|
+ this.changePlayProgress(value <= this.innerAudioContext.duration ? value : this.innerAudioContext
|
|
|
+ .duration);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //开启循环播放
|
|
|
+ handleLoopPlay() {
|
|
|
+ this.isLoop = !this.isLoop;
|
|
|
+ if (this.isLoop) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '已开启循环播放',
|
|
|
+ duration: 1000
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ uni.showToast({
|
|
|
+ title: '取消循环播放',
|
|
|
+ duration: 1000
|
|
|
+ });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //更改播放进度
|
|
|
+ changePlayProgress(value) {
|
|
|
+ this.innerAudioContext.seek(value);
|
|
|
+ this.sliderIndex = value;
|
|
|
+ this.currentTimeText = this.getFormateTime(value);
|
|
|
+ },
|
|
|
+ //秒转换为00:00:00
|
|
|
+ getFormateTime(time) {
|
|
|
+ let ms = time * 1000; // 1485000毫秒
|
|
|
+ let date = new Date(ms);
|
|
|
+
|
|
|
+ // 注意这里是使用的getUTCHours()方法,转换成UTC(协调世界时)时间的小时
|
|
|
+ let hour = date.getUTCHours();
|
|
|
+ // let hour = date.getHours(); 如果直接使用getHours()方法,则得到的时分秒格式会多出来8个小时(在国内开发基本都是使用的是东八区时间),getHours()方法会把当前的时区给加上。
|
|
|
+ let minute = date.getMinutes();
|
|
|
+ let second = date.getSeconds();
|
|
|
+
|
|
|
+ let formatTime =
|
|
|
+ `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:${second.toString().padStart(2, '0')}`;
|
|
|
+
|
|
|
+ return formatTime;
|
|
|
+ },
|
|
|
+ handleCollec() {
|
|
|
+ this.$emit('audioCollec');
|
|
|
+ },
|
|
|
+ handleShare() {
|
|
|
+ this.$emit('audioShare');
|
|
|
+ },
|
|
|
+ },
|
|
|
+ onUnload() {
|
|
|
+ this.audioDestroy()
|
|
|
+ },
|
|
|
+ onHide() {
|
|
|
+ this.audioDestroy()
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ this.audioDestroy()
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.control {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ padding: 0 30px;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.audio_container {
|
|
|
+ box-shadow: 0 0 5px #c3c3c3;
|
|
|
+ padding: 15px 10px 15px 10px;
|
|
|
+
|
|
|
+ .audio-title {
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .uni-noticebar {
|
|
|
+ padding: 0px;
|
|
|
+ padding-right: 25px;
|
|
|
+ margin-bottom: 0px;
|
|
|
+ display: inline-block;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ .audio-subTitle {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ font-size: 20px;
|
|
|
+ color: blue;
|
|
|
+ }
|
|
|
+
|
|
|
+ .speed-text {
|
|
|
+ position: absolute;
|
|
|
+ top: 0px;
|
|
|
+ left: 15px;
|
|
|
+ right: 0;
|
|
|
+ color: #475266;
|
|
|
+ font-size: 8px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .uni-grid-icon {
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+</style>
|