This commit is contained in:
2024-10-15 11:35:35 +08:00
parent 0ba0738ef9
commit 95365adddc
65 changed files with 13063 additions and 9746 deletions

View File

@@ -0,0 +1,461 @@
<template>
<view class="audio_container">
<view class="audio-title"
style="width: 100%; text-align: left; font-size: 36rpx;font-weight: bold;padding: 0rpx 0rpx; position: relative;">
<uni-notice-bar single :scrollable="titleScroll" :size="titleFontSize"
:background-color="titleBackgroundColor" :color="titleColor" :speed="titleScrollSpeed" :text="title"
class="uni-noticebar" style="padding: 0px; margin-bottom: 0px;">
</uni-notice-bar>
<uni-icons v-show="isCollectBtn" @click="handleCollec" type="heart" size="20"
style="color:#848484; position: absolute;top: 0rpx;right: 0px;"></uni-icons>
</view>
<view class="audio-subTitle"
:style="'font-size: '+subTitleFontSize+';font-weight: bold;padding: 0rpx 0rpx 4rpx 0rpx;position: relative;'">
<uni-notice-bar single :scrollable="titleScroll" :size="titleFontSize"
:background-color="titleBackgroundColor" :color="subTitleColor" :speed="titleScrollSpeed"
:text="subTitle" class="uni-noticebar">
</uni-notice-bar>
<uni-icons v-show="isShareBtn" @click="handleShare" type="redo" size="20"
style="color:#848484;position: absolute;top: 0rpx;right: 0px;"></uni-icons>
</view>
<view>
<slider :backgroundColor='backgroundColor' :activeColor='activeColor' @change="handleSliderChange"
:value="sliderIndex" :max="maxSliderIndex" block-color="#343434" block-size="16" />
</view>
<view style="padding: 0rpx 15rpx 0rpx 15rpx ; display: block; ">
<view style="float: left; font-size: 20rpx;color:#848484;">
{{currentTimeText}}
</view>
<view style="float: right;font-size: 20rpx;color:#848484;">
{{totalTimeText}}
</view>
</view>
<view style="margin-top: 70rpx;">
<uni-grid :column="4" :showBorder="false" :square="false">
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleFastRewind" src="../../static/images/get-back.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleChangeAudioState" v-show="!isPlaying" src="../../static/images/play.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
<image @tap="handleChangeAudioState" v-show="isPlaying" src="../../static/images/pause.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleFastForward" src="../../static/images/fast-forward.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleLoopPlay" src="../../static/images/Loop.svg"
style="width: 48rpx;height: 48rpx; top:6rpx; ">
</image>
</view>
</uni-grid-item>
</uni-grid>
</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,
default: '默认文件名'
},
//标题默认字体大小
titleFontSize: {
type: Number,
default: 35
},
//标题文字颜色
titleColor: {
type: String,
default: '#303030'
},
//标题背景色
titleBackgroundColor: {
type: String,
default: 'white'
},
//标题是否滚动
titleScroll: {
type: Boolean,
default: false
},
//标题滚动速度
titleScrollSpeed: {
type: Number,
default: 100
},
subTitle: {
type: String,
default: '默认文件名'
},
subTitleColor: {
type: String,
default: '#6C7996'
},
subTitleFontSize: {
type: String,
default: "30rpx"
},
//是否自动播放
autoplay: {
type: Boolean,
default: false
},
//滑块左侧已选择部分的线条颜色
activeColor: {
type: String,
default: '#7C7C7C'
},
//滑块右侧背景条的颜色
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 emptyThe 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)
//将当前音频长度秒转换为000000格式
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;
//将当前音频长度秒转换为000000格式
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>
.audio_container {
box-shadow: 0 0 10rpx #c3c3c3;
padding: 30rpx 20rpx 30rpx 20rpx;
.audio-title {
font-size: 28rpx;
}
.uni-noticebar {
padding: 0px;
padding-right: 50rpx;
margin-bottom: 0px;
display: inline-block;
}
.audio-subTitle {
width: 100%;
text-align: left;
font-size: 40rpx;
color: blue;
}
.speed-text {
position: absolute;
top: 0rpx;
left: 30rpx;
right: 0;
color: #475266;
font-size: 16rpx;
font-weight: 600;
}
.uni-grid-icon {
text-align: center;
}
}
</style>

View File

@@ -0,0 +1,422 @@
<template>
<view class="audio_container">
<!-- video标签 -->
<video id="videoPlayer" ref="videoPlayer" :src="src" :autoplay="autoplay" :muted="false"
style="width: 1rpx;height:1rpx;opacity: .1;" class="videoPlay" @loadedmetadata="onCanplay"
@timeupdate="onTimeUpdate" @error="errorFn" ></video>
<view class="audio-title"
style="width: 100%; text-align: left; font-size: 36rpx;font-weight: bold;padding: 0rpx 0rpx;position: relative;">
<uni-notice-bar single :scrollable="titleScroll" :size="titleFontSize"
:background-color="titleBackgroundColor" :color="titleColor" :speed="titleScrollSpeed" :text="title" style="padding-right: 50rpx;">
</uni-notice-bar>
<uni-icons v-show="isCollectBtn" @click="handleCollec" type="heart" size="20" style="color:#848484; position: absolute;top: 0rpx;right: 0px;" ></uni-icons>
</view>
<view class="audio-subTitle"
:style="'font-size: '+subTitleFontSize+';font-weight: bold;padding: 0rpx 0rpx 4rpx 0rpx;position: relative;'">
<uni-notice-bar single :scrollable="titleScroll" :size="titleFontSize"
:background-color="titleBackgroundColor" :color="subTitleColor" :speed="titleScrollSpeed"
:text="subTitle" style="padding-right: 50rpx;">
</uni-notice-bar>
<uni-icons v-show="isShareBtn" @click="handleShare" type="redo" size="20" style="color:#848484;position: absolute;top: 0rpx;right: 0px;" ></uni-icons>
</view>
<view>
<slider :backgroundColor='backgroundColor' :activeColor='activeColor' @change="handleSliderChange"
:value="sliderIndex" :max="maxSliderIndex" block-color="#343434" block-size="16" />
</view>
<view style="padding: 0rpx 15rpx 0rpx 15rpx ; display: block; ">
<view style="float: left; font-size: 20rpx;color:#848484;">
{{currentTimeText}}
</view>
<view style="float: right;font-size: 20rpx;color:#848484;">
{{totalTimeText}}
</view>
</view>
<view style="margin-top: 70rpx;">
<uni-grid :column="5" :showBorder="false" :square="false">
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleChageSpeed" src="../../static/images/multiple.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
<text class="speed-text">{{playSpeed}}</text>
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleFastRewind" src="../../static/images/get-back.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleChangeAudioState" v-show="!isPlaying" src="../../static/images/play.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
<image @tap="handleChangeAudioState" v-show="isPlaying" src="../../static/images/pause.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleFastForward" src="../../static/images/fast-forward.svg"
style="width: 48rpx;height: 48rpx;top:6rpx;">
</image>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="uni-grid-icon">
<image @tap="handleLoopPlay" src="../../static/images/Loop.svg"
style="width: 48rpx;height: 48rpx; top:6rpx; ">
</image>
</view>
</uni-grid-item>
</uni-grid>
</view>
</view>
</template>
<script>
export default {
name: 'my-video',
//audioPlay开始播放
//audioPause停止播放
//audioEnd音频自然播放结束事件
//audioCanplay音频进入可以播放状态但不保证后面可以流畅播放
//change播放状态改变 返回值false停止播放 true开始播放
emits: ['audioPlay', 'audioPause', 'audioEnd', 'audioCanplay', 'change'],
props: {
//标题文字
title: {
type: String,
default: ''
},
//标题默认字体大小
titleFontSize: {
type: Number,
default: 35
},
//标题文字颜色
titleColor: {
type: String,
default: '#303030'
},
//标题背景色
titleBackgroundColor: {
type: String,
default: 'white'
},
//标题是否滚动
titleScroll: {
type: Boolean,
default: false
},
//标题滚动速度
titleScrollSpeed: {
type: Number,
default: 100
},
subTitle: {
type: String,
default: ''
},
subTitleColor: {
type: String,
default: '#6C7996'
},
subTitleFontSize: {
type: String,
default: "30rpx"
},
autoplay: {
type: Boolean,
default: false
},
//滑块左侧已选择部分的线条颜色
activeColor: {
type: String,
default: '#7C7C7C'
},
//滑块右侧背景条的颜色
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: null,
// 后台音频控制器
backAudio:null,
}
},
created() {
// 获取 video 对象
this.innerAudioContext = uni.createVideoContext("videoPlayer", this);
},
async mounted() {
this.innerAudioContext.src = typeof(this.src) == 'string' ? this.src : this.src[0];
},
methods: {
//音频进入可以播放状态,但不保证后面可以流畅播放
onCanplay(e){
this.IsReadyPlay = true;
let duration=e.detail.duration;
this.$emit('audioCanplay');
//将当前音频长度秒转换为000000格式
this.totalTimeText = this.getFormateTime(duration);
this.maxSliderIndex = parseFloat(duration).toFixed(2);
// #ifdef MP
this.totalTimeText = parseFloat(duration).toFixed(2);
this.maxSliderIndex = parseFloat(duration).toFixed(2);
// #endif
},
// 音频播放事件处理函数 (持续触发) - 获取当前播放时长
onTimeUpdate(e) {
this.sliderIndex = parseFloat(e.detail.currentTime).toFixed(2);
this.currentTimeText = this.getFormateTime(e.detail.currentTime);
//如果已经播放到结尾,回到音频开始
if(this.sliderIndex==this.maxSliderIndex)
{
let prevState=this.isPlaying;
this.sliderIndex=0;
this.changePlayProgress(0);
this.audioPause();
//如果开启循环播放,且结束前还是播放状态
if(this.isLoop && prevState)
{
this.audioPlay();
}
}
},
//销毁innerAudioContext()实例
audioDestroy() {
if (this.innerAudioContext) {
this.innerAudioContext=null;
this.isPlaying = false;
}
},
//点击变更播放状态
handleChangeAudioState() {
if (this.isPlaying && !this.innerAudioContext.paused) {
this.audioPause();
} else {
this.audioPlay();
}
},
//开始播放
audioPlay(){
this.innerAudioContext.play();
this.isPlaying=true;
this.$emit('audioPlay')
this.$emit('change', {
state: true
});
},
//暂停播放
audioPause(){
this.innerAudioContext.pause();
this.isPlaying=false;
this.$emit('audioPause');
this.$emit('change', {
state: 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.maxSliderIndex ? value : this.maxSliderIndex);
}
},
//开启循环播放
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');
},
errorFn(){
this.$emit('change', {
state: false
});
this.audioPause();
this.$emit('error');
}
},
onUnload() {
this.audioDestroy()
},
onHide() {
this.audioDestroy()
},
beforeDestroy() {
this.audioDestroy()
}
}
</script>
<style lang="scss" scoped>
.audio_container {
box-shadow: 0 0 10rpx #c3c3c3;
padding: 15rpx 15rpx 40rpx 15rpx;
.audio-title {
font-size: 28rpx;
}
.uni-noticebar {
padding: 0px;
}
.audio-subTitle {
width: 100%;
text-align: left;
font-size: 40rpx;
color: blue;
}
.speed-text {
position: absolute;
top: 0rpx;
left: 30rpx;
right: 0;
color: #475266;
font-size: 16rpx;
font-weight: 600;
}
.uni-grid-icon {
text-align: center;
}
}
</style>