| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 | <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>
 |