需求:应项目需要,要实现文字转语音的功能,现有的audio播放器组件,样式不满足需要,则自定义一个播放器
话不多说,直接看效果图
功能: 目前已实现倍数播放,暂停播放,拖动进度条播放等功能,后续还会完善
上代码:
wxml:
<view class='audioPlayer'>
<view class="poster">
<image src="{{curPoster}}" mode="aspectFitll" />
</view>
<view class="title">
<text>{{curTitle}}</text>
</view>
<view class='player'>
<view class='audioControls'>
<!-- 进度条 -->
<view class='slider'>
<slider bindchange='sliderChange' block-color="#000000" activeColor='#000000' backgroundColor="#aeaeae" block-size="12" value='{{audioTime}}' />
</view>
<!-- 时间 -->
<view class='time'>
<view class="timeLeft">{{showTime1}}</view>
<view class="timeRight">{{showTime2}}</view>
</view>
<!-- 倍数弹窗 -->
<view>
<view class="rate" bindtap='actionSheetTap'>{{playbackRate == 1? "倍数" : playbackRate+ "倍" }}</view>
<action-sheet hidden='{{actionSheetHidden}}' bindchange='actionSheetChange'>
<block wx:for='{{actionSheetRate}}'>
<!-- 参数名字叫 rate -->
<action-sheet-item class="rateNum" bindtap="selectRate" data-rate="{{item}}">{{item == 1? "正常" : item+ "倍" }}</action-sheet-item>
</block>
<action-sheet-cancel>取消</action-sheet-cancel>
</action-sheet>
</view>
</view>
</view>
<!-- 播放控件 -->
<view class="btns">
<!-- <image mode="widthFix" class="previous" src="/images/previous.png" bindtap="previousFun"></image> -->
<label class="play">
<image mode="widthFix" src="{{ isPlayAudio == true ? '/images/zanting.png' : '/images/bofang.png'}}" bindtap="playAudio"></image>
</label>
<!-- <image mode="widthFix" class="next" src="/images/next.png" bindtap="nextFun"></image> -->
</view>
</view>
wxss:
/* pages/audio/audio.wxss */
.flex{
float: left;
width: 100%;
position: relative;
}
.audioPlayer{
width: 100%;
height: 114rpx;
box-sizing: border-box;
padding: 20rpx 30rpx;
/* background: #f4f4f4; */
}
/* 图片 */
.poster{
width: 680rpx;
height: 450rpx;
border-radius: 12rpx;
margin: 0 auto;
}
.poster image{
width: 100%;
height: 100%;
}
/* 标题 */
.title{
height: 50rpx;
line-height: 50rpx;
font-size: 36rpx;
margin-top: 80rpx;
padding: 0 0 0 10rpx;
color: #666;
}
.player{
width: 100%;
height: 100%;
position: relative;
margin-top: 80rpx;
}
.audioBack{
width: 100%;
height: 100%;
}
.audioControls{
width: 100%;
height: 100rpx;
/* background: #f4f4f4; */
color: #666;
font-size: 6pt;
text-align: center;
}
/* .audioControls .bottom{
width: 84rpx;
height: 100%;
float: left;
}
.audioControls .bottom image{
margin-top: 15rpx;
margin-left: 15rpx;
width: 54rpx;
height: 54rpx;
} */
.audioControls .slider{
/* width: calc(100% - 84rpx); */
width: 100%;
height: 100%;
float: left;
}
.slider slider{
width: 95%;
margin-left: 4%;
margin-right: 0;
}
.audioControls .time{
width: calc(100% - 20rpx);
height: 30rpx;
position: absolute;
bottom: -10px;
right: 0px;
font-size: 16px;
color: #aeaeae;
}
.timeLeft{
float: left;
height: 20px;
line-height: 20px;
}
.timeRight{
float: right;
height: 20px;
line-height: 20px;
}
/* 倍数按钮 */
.rate{
font-size: 18px;
color: #7e7c7c;
}
.rateNum{
height: 60rpx;
line-height: 60rpx;
}
/* 播放控件 */
.btns{
height: 100rpx;
display: flex;
padding: 10rpx 40rpx;
justify-content: space-around;
align-items: center;
margin-top: 150rpx;
}
.btns image{
width: 100rpx;
}
page{
background: #ffffff;
}
js:
const app = getApp()
const innerAudioContext = wx.createInnerAudioContext();
Page({
data: {
audiolist: [
{
audiosrc: "http://lcjl-uat-bucket.oss-cn-beijing.aliyuncs.com/2024/202402/20240223/9ad75843327248b78bfbfcee4791e9f1.mp3",
poster: "https://cn.bing.com/th?id=OVFT.h-IoQ6aCPK-kCyaQhiEAeS&w=186&h=88&c=7&rs=2&qlt=80&pid=PopNow",
title:"文章标题1"
},
{
audiosrc: "http://lcjl-uat-bucket.oss-cn-beijing.aliyuncs.com/2024/202402/20240223/2470caa499f44f598a7fcce3e00e35c8.mp3",
poster: "https://cn.bing.com/th?id=OVFT.h-IoQ6aCPK-kCyaQhiEAeS&w=186&h=88&c=7&rs=2&qlt=80&pid=PopNow",
title:"文章标题2"
},
{
audiosrc: 'https://tts-async-audio-sh-1300466766.cos.ap-shanghai.myqcloud.com/20240222%2F1309824489%2Fgz-64e0d0c4-300c-40a8-a544-01f9a7c111ed.mp3?q-sign-algorithm=sha1&q-ak=AKIDJXcaKs2w4vZw5zTCrHRM7dOwre9Xk9MJ&q-sign-time=1708590317%3B1709195117&q-key-time=1708590317%3B1709195117&q-header-list=host&q-url-param-list=&q-signature=3bf4929d4f8ef86b2bb478cbd4fe5e2948ae01d1',
poster: "https://cn.bing.com/th?id=OVFT.h-IoQ6aCPK-kCyaQhiEAeS&w=186&h=88&c=7&rs=2&qlt=80&pid=PopNow",
title:"文章标题3"
},
],
curPoster: "",
curTitle: "",
isPlayAudio: false, // 是否在播放
audioSeek: 0,
audioDuration: 0,
showTime1: '00:00',
showTime2: '00:00',
audioTime: 0,
playbackRate: 2,
actionSheetHidden: true, // 倍数弹窗
actionSheetRate:[0.5, 1, 1.5, 2]
},
onLoad: function () {
},
onShow: function () {
this.Initialization();
this.loadaudio();
},
//初始化播放器,获取duration
Initialization() {
var that = this;
if (this.data.audiolist[0].audiosrc.length != 0) {
// 设置标题 potstrt
that.setData({
curPoster: this.data.audiolist[0].poster,
curTitle: this.data.audiolist[0].title
})
//设置src
innerAudioContext.src = this.data.audiolist[0].audiosrc;
// 设置倍数 0.5 ~ 2
innerAudioContext.playbackRate=this.data.playbackRate;
//运行一次
// innerAudioContext.play();
// innerAudioContext.pause();
innerAudioContext.onCanplay(() => {
//初始化duration
innerAudioContext.duration
setTimeout(function () {
//延时获取音频真正的duration
var duration = innerAudioContext.duration;
var min = parseInt(duration / 60);
var sec = parseInt(duration % 60);
if (min.toString().length == 1) {
min = `0${min}`;
}
if (sec.toString().length == 1) {
sec = `0${sec}`;
}
that.setData({ audioDuration: innerAudioContext.duration, showTime2: `${min}:${sec}` });
}, 1000)
})
}
},
//拖动进度条事件
sliderChange(e) {
var that = this;
innerAudioContext.src = this.data.audiolist[0].audiosrc;
//获取进度条百分比
var value = e.detail.value;
this.setData({ audioTime: value });
var duration = this.data.audioDuration;
//根据进度条百分比及歌曲总时间,计算拖动位置的时间
value = parseInt(value * duration / 100);
//更改状态
this.setData({ audioSeek: value, isPlayAudio: true });
//调用seek方法跳转歌曲时间
innerAudioContext.seek(value);
//播放歌曲
innerAudioContext.play();
},
//播放、暂停按钮
playAudio() {
//获取播放状态和当前播放时间
var isPlayAudio = this.data.isPlayAudio;
var seek = this.data.audioSeek;
innerAudioContext.pause();
//更改播放状态
this.setData({ isPlayAudio: !isPlayAudio })
if (isPlayAudio) {
//如果在播放则记录播放的时间seek,暂停
this.setData({ audioSeek: innerAudioContext.currentTime });
} else {
//如果在暂停,获取播放时间并继续播放
innerAudioContext.src = this.data.audiolist[0].audiosrc;
if (innerAudioContext.duration != 0) {
this.setData({ audioDuration: innerAudioContext.duration });
}
//跳转到指定时间播放
innerAudioContext.seek(seek);
innerAudioContext.play();
}
},
loadaudio() {
var that = this;
//设置一个计步器
this.data.durationIntval = setInterval(function () {
//当歌曲在播放时执行
if (that.data.isPlayAudio == true) {
//获取歌曲的播放时间,进度百分比
var seek = that.data.audioSeek;
var duration = innerAudioContext.duration;
var time = that.data.audioTime;
time = parseInt(100 * seek / duration);
//当歌曲在播放时,每隔一秒歌曲播放时间+1,并计算分钟数与秒数
var min = parseInt((seek + 1) / 60);
var sec = parseInt((seek + 1) % 60);
//填充字符串,使3:1这种呈现出 03:01 的样式
if (min.toString().length == 1) {
min = `0${min}`;
}
if (sec.toString().length == 1) {
sec = `0${sec}`;
}
var min1 = parseInt(duration / 60);
var sec1 = parseInt(duration % 60);
if (min1.toString().length == 1) {
min1 = `0${min1}`;
}
if (sec1.toString().length == 1) {
sec1 = `0${sec1}`;
}
//当进度条完成,停止播放,并重设播放时间和进度条
if (time >= 100) {
innerAudioContext.stop();
that.setData({ audioSeek: 0, audioTime: 0, audioDuration: duration, isPlayAudio: false, showTime1: `00:00` });
return false;
}
//正常播放,更改进度信息,更改播放时间信息
that.setData({ audioSeek: seek + 1, audioTime: time, audioDuration: duration, showTime1: `${min}:${sec}`, showTime2: `${min1}:${sec1}` });
}
}, 500)
},
onUnload: function () {
//卸载页面,清除计步器
clearInterval(this.data.durationIntval);
},
// 倍数弹窗
actionSheetTap: function() {
this.setData({
actionSheetHidden:false
});
},
// 取消弹窗
actionSheetChange: function (e) {
console.log('取消按钮被点击');
this.setData({
actionSheetHidden: true
});
},
// 选择倍数
selectRate(e){
let rate = e.currentTarget.dataset.rate
this.setData({
playbackRate:rate,
actionSheetHidden:true
})
this.Initialization()
}
})
参照:https://blog.csdn.net/qq_41756580/article/details/103296701