\"\"

 效果图是这样的,网上和线上小程序大部分都是用slider做的,方便快捷。

 但是如果想变粗线条就无法设置了,所以自己写了一个这样的东西分享记录一下。

 

需求:

1、开始播放后,每秒钟自动变化进度条。根据音频时长,进度条长度计算位移多少。
2、手指拖拽时候,时间随拖拽变化,方便定位到那个时间点然后从那一刻开始播放。
3、适配机型宽度,整体效果一致。
4、可以暂停,可以暂停后拖拽后在播放。加载中的时候,显示加载icon。
5、显示缓存进度条,用户可以知道当前缓存多少。

 

 


实现思路和方式:

1、用三个div分别代表 进度条底儿、当前缓存(红色)、当前进度条位置,然后通过小程序动画 移动后两个,通过定时器去每秒钟移动,进度条用transform:translateX 比较流畅,缓存用width比较实用。

2、进度条div里面在来个div绑定上3个touch事件,然后让进度条整体translateX(-100%)

3、计算 rpx和和px的比值 如果你的设计稿是750 ,就用你   设备宽度/750 这样才可以计算位置。因为小程序的touch只能拿到px
也就是clientX的值。
4、计算好拖动时候的动画,和左右两边的限制。

 

代码:

<template>

 

<div class=\"audio_box\">

<div class=\"currentTimeBack\">{{currentTimeBack}}</div>

<div class=\"currentTimeForward\">{{currentTimeForward}}</div>

<!-- <div class=\"audio_details_box\">

<div class=\"words_count\">单词数: {{audioData.wordsCount}}</div>

<div class=\"switch_en_ch\">显示中文释义</div>

</div> -->

<!-- <text class=\"current-process\">{{current_process}}</text> -->

<div class=\"sliderbox\">

<div class=\"sliderbg\"></div>

<div class=\"sliderbufferedbg\" v-bind:style=\"{width:bufferedWidthVal}\"></div>

<div class=\"sliderLine\" id=\"linebox\" :animation=\"animatedata\">

<div class=\"sliderPoint\" @touchstart=\"touchLineStart\" @touchmove=\"touchLineMove\" @touchend=\"toudLineEnd\"></div>

</div>

</div>

<div class=\"audio_control_box\">

<img @click=\"prev\" mode=\"widthFix\" src=\"/static/audio/audio_pre.png\" class=\"audio_pre\"/>

<img @click=\"audio_play\" v-show=\"!waiting\" mode=\"widthFix\" :src=\"[is_play?\'/static/audio/audio_pause.png\': \'/static/audio/audio_play.png\']\" class=\"audio_play_bt\" />

<img mode=\"widthFix\" v-show=\"waiting\" src=\"/static/audio/audio_waiting.png\" class=\"audio_play_bt waitingbt\" />

<img @click=\"next\" mode=\"widthFix\" src=\"/static/audio/audio_next.png\" class=\"audio_next\"/>

</div>

</div>

</template>

< >

export default {

porps: [\'audioManager\'],

data() {

return {

isIos: null,

waiting: false,

dpi: -1,

screenW: wx.getSystemInfoSync().screenWidth,

audioManager: null,

is_play: false,

currentTimeForward: \'\',

newCurentTime: -1,

currentTimeBack: \'\',

audioData: {

duration: 0

},

animatedata: {},

timer: null,

isTouching: false,

bufferedVal: 0,

bufferedWidthVal: 0

};

},

async () {

this.isIos = await global.isIos();

this.audioManager = wx.getBackgroundAudioManager();

this.dpi = parseFloat((this.screenW / 750).toFixed(3)); // dpi指数

const url =

\'https://ssl-public.langlib.com/pe/aha/test/GRE_demo.mp3?jjj=44\';

this.audioData.url = url;

this.audioData. = \'雅思托福串讲音频\';

this.audioData.lessonName = \'langlib\';

// 置灰上一首下一首

// if (response.preArticleId == 0) {

// that.setData({

// is_first_page: true

// });

// }

// if (response.nextArticleId == 0) {

// that.setData({

// is_last_page: true

// });

// }

this.audioManager.onSeeking(() => {

console.log(\'onSeek\');

});

this.audioManager.onPlay(() => {

console.log(\'onplay\');

clearInterval(this.timer);

this.is_play = true;

this.waiting = false;

this.setDuration();

this.timer = setInterval(() => {

this.setDuration();

}, 1000);

});

this.audioManager.onCanplay(() => {

console.log(\'oncanplay\');

this.waiting = false;

});

// 背景音频播放进度更新事件

this.audioManager.onTimeUpdate(() => {

});

// 背景音频播放完毕

this.audioManager.onEnded(() => {

clearInterval(this.timer);

console.log(\'audioEnd\');

this.lineAnimate(\'-2px\');

});

this.audioManager.onPause(() => {

console.log(\'onPause\');

this.is_play = false;

});

this.audioManager.onWaiting(() => {

console.log(\'onwating\');

this.waiting = true;

});

},

 

methods: {

touchLineStart() {

console.log(\'touchLineStart\');

this.isTouching = true;

clearInterval(this.timer);

},

touchLineMove(e) {

this.isTouching = true;

const rate = e.clientX / 750;

const moveLeftpx = e.clientX;

const boxWidth = 560 * this.dpi;

const limitLeftpx = (this.screenW - boxWidth) / 2;

if (

moveLeftpx <= limitLeftpx - 1.5 ||

e.clientX >= (limitLeftpx + boxWidth) - 2

) {

return;

}

const sliderValue = `${moveLeftpx - limitLeftpx - boxWidth}px`;

this.lineAnimate(sliderValue);

// 不仅要让滑块运动,在滑动过程中 当前时间也要跟随变动,这样在抬起时可以定点播放

// 1.计算当前滑动的点 占整个进度条长度(px)的百分比

// 2.百分比 * 当前总音频时长 = 当前点所在的时长

// 3.当比例小于1或者大于1 代表 超出了范围 就return吧

const movePercent = (moveLeftpx - limitLeftpx) / boxWidth;

this.newCurentTime =

movePercent * this.audioManager.duration > 0

? movePercent * this.audioManager.duration

: 1;

 

if (movePercent < 0 || movePercent > 1) return;

this.currentTimeForward = this.stotime(this.newCurentTime);

},

toudLineEnd(e) {

console.log(this.newCurentTime);

console.log(this.audioManager.buffered);

if (this.audioManager.paused && this.newCurentTime) {

this.isTouching = false;

this.is_play = false;

this.audio_play(this.newCurentTime);

return;

}

if (this.newCurentTime) {

this.audioManager.seek(this.newCurentTime);

this.is_play = true;

}

this.isTouching = false;

},

// 点击播放暂停

audio_play(newCurentTime) {

if (this.is_play) {

this.is_play = false;

this.audioManager.pause();

clearInterval(this.timer);

} else {

this.is_play = true;

if (typeof newCurentTime === \'number\') {

this.audioManager.seek(newCurentTime);

this.audioManager.play();

return;

}

// if (this.audioManager.paused) {

// this.audioManager.play();

// return;

// }

this.playAudio();

}

},

// 上一首

prev() {

 

},

// 下一首

next() {

 

},

playAudio() {

if (this.isIos) this.waiting = true;

this.audioManager. = this.audioData. ;

this.audioManager.src = this.audioData.url;

this.audioManager.play();

},

setDuration() {

// 显示 播放时间 音频时长

if (this.isTouching) return;

const currentTimeForward = this.audioManager.currentTime;

const currentTimeBack = this.audioManager.duration || 0;

const brffer = this.audioManager.buffered;

this.currentTimeForward = this.stotime(currentTimeForward);

this.currentTimeBack = this.stotime(currentTimeBack);

// 让当前的进度条 滑动到对应的位置

// 1、当前音频进行到了总音频的占比

// 2、计算进度条应该位移多少

// 3、使用动画让进度条移动

// 4、如果在我手动去滑动进度条的时候,就别走动画了

const linePointMovePercent = currentTimeForward / currentTimeBack;

const boxWidth = 560 * this.dpi;

const linePointMovePx = `${(linePointMovePercent * boxWidth).toFixed() -

boxWidth}px`;

// console.log(`${boxWidth}长px left:${linePointMovePx}`);

console.log(brffer);

if (brffer && this.audioManager.duration) {

this.bufferedVal = this.audioManager.buffered;

this.bufferedWidthVal =

`${parseFloat(brffer / currentTimeBack) *

600 *

this.dpi}px`;

}

this.lineAnimate(linePointMovePx);

},

lineAnimate(movepx) {

const animation = wx.createAnimation({

duration: 250,

timingFunction: \'ease-out\'

});

const animate = animation.translate(`${movepx}`, \'-50%\').step();

this.animatedata = animate.export();

},

// 时间转换

stotime(s) {

let t = \'\';

let ss = s;

if (ss > -1) {

if (s > 0 && s < 1) {

ss = 1;

}

const min = Math.floor(ss / 60) % 60;

const sec = Math.floor(ss % 60);

if (min < 10) {

t += \'0\';

}

t += `${min}:`;

if (sec < 10) {

t += \'0\';

}

t += sec;

}

return t;

}

}

};

</ >

 

<style scoped>

.box {

width: 200rpx;

height: 20rpx;

background: red;

position: absolute;

top: 50%;

left: 0;

}

.audio_box {

width: 100vw;

height: 400rpx;

position: absolute;

bottom: 0;

left: 0;

background: #fff;

}

.audio_details_box {

width: 750rpx;

height: 90rpx;

background: #ccc;

display: flex;

align-items: center;

justify-content: space-between;

}

.words_count,

.switch_en_ch {

font-size: 30rpx;

color: rgba(51, 51, 51);

}

.words_count {

margin-left: 40rpx;

}

.switch_en_ch {

margin-right: 40rpx;

}

.sliderbox {

width: 600rpx;

height: 50rpx;

margin: 20rpx auto;

position: relative;

overflow-x: hidden;

}

.slider,

.sliderbg,

.sliderbufferedbg,

.sliderLine {

width: 600rpx;

height: 20rpx;

position: absolute;

top: 50%;

margin: 0;

transform: translateY(-50%);

left: 0;

}

.sliderbufferedbg {

background: red;

width: 0;

z-index: 4;

}

.slider {

top: 60rpx;

}

.sliderbg {

background: rgba(206, 206, 206, 1);

z-index: 3;

}

.sliderLine {

background: rgba(64, 64, 64, 1);

transform: translate(calc(-100% + 36rpx), -50%);

z-index: 4;

}

.sliderPoint {

position: absolute;

right: -2rpx;

top: -10rpx;

width: 40rpx;

height: 40rpx;

background: rgba(64, 64, 64, 1);

border-radius: 50%;

}

.audio_control_box{

width: 80%;

height: 120rpx;

margin:0 auto;

display: flex;

align-items: center;

justify-content:space-around;

}

.audio_play_bt,.audio_pre,.audio_next {

width: 40rpx;

height: 40rpx;

}

.currentTimeBack,

.currentTimeForward {

position: absolute;

right: 30rpx;

top: 60rpx;

font-size: 32rpx;

font-weight: 500;

color: black;

width: 100rpx;

height: 50rpx;

text-align: center;

}

.currentTimeForward {

left: 30rpx;

}

.waitingbt{

animation:rotate 3s linear infinite;

 

}

@key s rotate2{

from{transform: rotate(0deg)}

to{transform: rotate(359deg)}

}

</style>


最后的样子:


\"\"

收藏 打印