angular11实现自定义语音播放器
本播放器实现了播放、暂停、点击进度条播放、拖动到指定位置播放、指定播放时间范围等等。具体请看代码。
import { Component, OnInit } from '@angular/core';
import { fromEvent } from 'rxjs';
import * as _ from 'lodash';
class Audio implements OnInit {
audio: HTMLAudioElement;
duration: number;
startTime = 0;
endTime = 0;
moveDistance = 0;
dragDistance = 0;
barWidth = 0;
sliderWidth = 0;
canSlideWidth = 0;
givedEndTime = 0;
url =
'https://autotest-qi.obs.cn-north-7.ulanqab.huawei.com:443/%E8%AF%AD%E9%9F%B3%E6%96%87%E4%BB%B6_%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E9%A2%84%E7%BD%AE_%E5%8B%BF%E5%88%A0/2-2.mp3?AccessKeyId=7HU7YO4WE012PTZTVPTB&Expires=1619680596&x-obs-security-token=gQpjbi1ub3J0aC03hmp9srGjyHuP2p45iE1wULlzh5qFF6ZSTPthh8ND_JspOU6g8MkZ-tu-_nbvXMdXCxkPqbJQAm-yPSVNz2uNQbkjW-0EkyluhtuxY82L59hnghOq_eVPHR1prTpCq0ivaC12UbxQgzwD6eoEl-h7zcjrE2MJYz5xPRDSzFoG5VpKrlnmHNzsXPET90C_i0W0THm63MF7XmIeAwKZ_b25lJzgYdGnRR6GAi0Ga_U9dv7WAk1qvOk79bDjnpw9z0-wX7-7eHjtVLY5KKBH1XLaNHGKGp8bksmMP5P4fnyL8SS4oZ9n3fQpMgY0NGPJxMb9U5MKR1FCTgTirh7GQagSPIKkufIk1yioq1_DMKmnYzy9eFCn5HZgIrfeupVg-CC6k0oMYZb0CsaF9J8IXiocw1YAecmOqMvd0JFd-pv7pXipEJYlEuZ7kMOlWAcB4lh09dY-o6L_8QDgA28B_8mBnh-LhiaqnKLjCiUeH-EX9WYyvkL8SA3RjtTOFdlLWE106K_2MhlLRRTTBh9XwjfmXysre8VcDTKKzYc9Runkt7Ckh9gGAlfMrWUdE4I1fsu2C58k1wyoLIfpEzMVomxOh0TiaCKjUkaT0-NPwuXSXFNoq8yf6cgCgsv3r5vmF38nTcDCeg0_8KPxdFJV77DqhH16VkzKgmiAJM9utNa33Q88cswyAt-_PfwNMO1v55_G9RaWgj2gwSV6ofJSiqBzlASNJz0_pwlh1_cVz5sqBds9oZTbcUiyLS8JUfBcUySaUlvoonjb3tEFJ1kOyVIP51vULQDUm6sXTjAle_O5cvFLej1a_JzI56kHoOU-xUTAKePKqIBjSYKszIJnMD5rzSFGRv1xzBwr0RTTdsv9VGLyce1sm4ZE3FwXSBTGrXZJNXFfqtShRqXXwYLxjmbG5kjIad1Hcj3LJ7Mq1i3tVhiIkn6g7xb4R6RKE1CEcbI3hvP5MhII1Qo46u8mvdCi299uLFh2-tGwwHKI_BuMa5DPtBOBjUmXFgppjiPIlDuOZemHwfyUhHp2oIpTZhIuyMDhwK2na7DzfBwNMgEgk5-mWRyF4GubRbI5jUfgwacpPw%3D%3D&Signature=wsqj5ZnaH13J0DkdQ%2FKvnBnBeVA%3D';
constructor() {}
ngOnInit(): void {
this.audio = document.querySelector('audio');
this.initParam();
// 基于准备好的dom,初始化echarts实例
this.addPlayListener();
this.addCanplayListener();
this.addTimeupdateChange();
this.addPauseListener();
}
/**
* 获取播放条宽度
*/
initParam() {
const bar = document.querySelector('#bar') as HTMLElement;
const slider = document.querySelector('#slider') as HTMLElement;
this.barWidth = +bar.style.width.split('px')[0];
this.sliderWidth = +slider.style.width.split('px')[0];
this.canSlideWidth = this.barWidth - this.sliderWidth / 2;
}
/**
* 监听开始播放
*/
addPlayListener(): void {
fromEvent(this.audio, 'play').subscribe((res) => {
this.startTime = this.getCurrentTime();
});
}
/**
* 监听暂停播放
*/
addPauseListener(): void {
fromEvent(this.audio, 'pause').subscribe((res) => {
this.endTime = this.getCurrentTime();
});
}
/**
* 监听是否能播放
*/
addCanplayListener(): void {
fromEvent(this.audio, 'canplay').subscribe((res) => {
this.initTime();
});
}
/**
* 点击调整播放位置
*/
goto(event: MouseEvent) {
let position =
event.clientX -
(event.target as HTMLElement).parentElement.offsetLeft -
this.sliderWidth / 2;
const currentTime = this.distanceToTime(position);
this.toPlayTime(currentTime);
}
/**
* 时间改变的回调
*/
addTimeupdateChange(): void {
fromEvent(this.audio, 'timeupdate').subscribe((res) => {
// 是否在给定时间内播放
if (this.givedEndTime !== 0) {
let over = this.playRangeTime(this.endTime, this.givedEndTime);
if (over) {
this.givedEndTime = this.duration;
}
}
this.endTime = this.getCurrentTime();
this.moveDistance = this.timeToDistance(0, this.endTime);
});
}
/**
* 从给定时间点播放
*/
playFromGiveTime(start: number, end: number) {
this.toPlayTime(start);
this.play();
this.givedEndTime = end;
}
/**
* 当前进度播放范围内
*/
playRangeTime(current: number, end: number): boolean {
if (current > end) {
this.pause();
return true;
}
}
/**
* 初始化播放时间和当前进度
*/
initTime(): void {
// 获取播放总时间
this.duration = this.getPlayTime();
}
/**
* 获取播放长度
*/
getPlayTime(): number {
return this.audio.duration;
}
/**
* 获取当前播放进度
*/
getCurrentTime(): number {
return this.audio.currentTime;
}
/**
* 播放
*/
play(): void {
this.audio.play();
}
/**
* 暂停
*/
pause(): void {
this.audio.pause();
}
/**
* 点击播放圆点
*/
mouseclick(event: MouseEvent) {
event.stopPropagation();
}
/**
* 拖动
*/
mousedown(event: MouseEvent): void {
const currentX = event.clientX;
const slider = document.querySelector('#slider') as HTMLElement;
const leftVal = currentX - slider.offsetLeft;
const mousemove = fromEvent(document, 'mousemove').subscribe((event2) => {
const barLeft = (event2 as MouseEvent).clientX;
const move = barLeft - leftVal;
if (_.inRange(move, 0, this.canSlideWidth)) {
this.dragDistance = move;
const currentTime = this.distanceToTime(move);
this.toPlayTime(currentTime);
}
window.getSelection().removeAllRanges();
});
fromEvent(document, 'mouseup').subscribe(() => {
mousemove.unsubscribe();
});
}
/**
* 根据拖动距离设置当前播放时间
*/
toPlayTime(time): void {
this.audio.currentTime = time;
}
/**
* 时间转为距离
*/
timeToDistance(start, end): number {
return ((end - start) / this.duration) * this.canSlideWidth;
}
/**
* 距离转为时间
*/
distanceToTime(distance): number {
return (distance / this.canSlideWidth) * this.duration;
}
}
<audio [src]="url" controls style="display: none">
您的浏览器不支持 audio 标签。
</audio>
<div style="display: flex; align-items: center;margin-left: 100px;">
<div (click)="goto($event)" id="bar" style="height: 5px; width: 500px; background-color: aquamarine;position: relative;cursor: pointer;">
<div
style="height: 5px; background-color: red;position: absolute;top: 0;left: 0;"
[style.width]="moveDistance + 'px'"
>
<div id="slider" (click)="mouseclick($event)" (mousedown)="mousedown($event)" style="position: absolute;left: 100%;top:-150%;width: 20px;height: 20px;border-radius: 50%;background-color: aqua;cursor: pointer;"></div>
</div>
</div>
<span>{{ duration }}</span>
</div>
<button (click)="play()">播放</button>
<button (click)="pause()">暂停</button>
<button (click)="playFromGiveTime(5,10)">指定范围</button>
具体效果请编辑代码实现哈,有问题请留言,会及时回复的