由于最近开发 h5 项目需要,需要按设计原稿实现音频播放组件,但原始但音频播放又不符合项目需要,为此重新封装整理出来,为此分享
直接上图看效果
直接上源码
在 components 中创建 AudioItem,AudioItem 文件中添加 audioItem.js 文件
/**
* 音频播放组件
*/
import React, { Component } from "react";
import icon_play from "../Image/music.png"; //这个是项目设计稿定义的图片
import icon_pause from "../Image/stop3.png"; //这个是项目设计稿定义的图片
//时分秒转化为秒
const timeEvent = (e) => {
var time = e;
var len = time.split(":");
if (len.length == 3) {
var hour = time.split(":")[0];
var min = time.split(":")[1];
var sec = time.split(":")[2];
return Number(hour * 3600) + Number(min * 60) + Number(sec);
}
if (len.length == 2) {
var min = time.split(":")[0];
var sec = time.split(":")[1];
return Number(min * 60) + Number(sec);
}
if (len.length == 1) {
var sec = time.split(":")[0];
return Number(sec);
}
};
class AudioItem extends Component {
static defaultProps = {
src: "", // 音频地址
};
state = {
isCanPlay: false, // 判断音频是否加载完成
playStatus: false, // 播放状态, true 播放中, false 暂停中,
duration: 0, // 音频的时长
currentDuration: 0, // 当前的播放时长
};
audioItem = null; // 把dom暴露给外部使用
audio = new Audio(); // 一个音频对象
timer = null; // 做一个滑条的防抖
interval = null; // 定时查询播放时的当前时间
// 播放音频
play = () => {
this.audio.play();
this.interval = setInterval(() => {
const time = Math.floor(this.audio.currentTime);
if (time < this.state.duration) {
this.setState({
currentDuration: time,
});
} else {
// 播放结束后,直接重置播放时间,停止播放
// Toast.info('播放完毕');
clearInterval(this.interval);
this.audio.currentTime = 0;
this.audio.pause();
this.setState({
currentDuration: 0,
playStatus: false,
});
}
}, 1000);
};
// 暂停音频
pause = () => {
this.audio.pause();
if (this.interval) {
clearInterval(this.interval);
}
};
// 播放状态切换
handlePlayStatusChange = () => {
const { playStatus, isCanPlay } = this.state;
if (!playStatus) {
this.play();
} else {
this.pause();
}
this.setState({
playStatus: !playStatus,
});
};
handleSilderChange = (value) => {
if (this.timer) {
clearTimeout(this.timer);
}
// 0.2s之内没有改动就修改当前的时间,做一个播放的防抖
this.timer = setTimeout(() => {
this.pause();
this.audio.currentTime = value;
this.setState(
{
currentDuration: value,
},
() => {
if (this.state.playStatus) {
this.play();
}
}
);
}, 200);
};
// 根据秒数,返回对应的xx:xx的时间格式
getDurationString = (number) => {
let num = Number(number);
if (isNaN(num) || num <= 0) {
return "00:00";
}
if (num === Infinity) {
return "00:00";
}
if (num < 60) {
return `00:${num.toString().padStart(2, 0)}`;
} else if (num < 3600) {
const minute = Math.floor(num / 60);
const second = num % 60;
return `${minute.toString().padStart(2, 0)}:${second
.toString()
.padStart(2, 0)}`;
} else {
const hour = Math.floor(num / 3600);
const minute = Math.floor((num - hour * 3600) / 60);
const second = num - hour * 3600 - minute * 60;
return `${hour.toString().padStart(2, 0)}:${minute
.toString()
.padStart(2, 0)}:${second.toString().padStart(2, 0)}`;
}
};
init = (props) => {
const { src } = props || this.props;
if (!src) {
return;
}
this.audio.preload = "automatic";
this.audio.src = src;
this.audio.load();
// 监听音频的时长是否获取到了
this.audio.ondurationchange = () => {
const duration = Math.floor(this.audio.duration);
this.setState({
duration,
});
};
// 监听音频是否可以播放了
this.audio.oncanplay = () => {
const duration = Math.floor(this.audio.duration);
this.setState({
duration,
isCanPlay: true,
});
};
};
componentDidMount() {
this.init();
}
componentWillReceiveProps(nextProps) {
if (nextProps.src !== this.props.src) {
this.init(nextProps);
}
}
componentWillUnmount() {
if (this.timer) {
clearTimeout(this.timer);
}
if (this.interval) {
clearInterval(this.interval);
}
if (this.audio) {
this.audio.currentTime = 0;
this.audio.pause();
}
}
render() {
const { playStatus, duration } = this.state;
const btn_img = playStatus ? icon_pause : icon_play;
const durationStr = this.getDurationString(duration);
return (
<div ref={(audioItem) => (this.audioItem = audioItem)}>
<div
onClick={this.handlePlayStatusChange}
style={{
display: "flex",
justifyContent: "space-between",
width:
timeEvent(durationStr) < 5
? "100px"
: timeEvent(durationStr) < 10
? "150px"
: timeEvent(durationStr) < 15
? "175px"
: "200px",
height: "36px",
background: "#FFB91B",
borderRadius: "6px",
}}
>
<div>
<img
src={btn_img}
alt="icon"
style={{
paddingTop: "8.5px",
paddingLeft: "9px",
}}
/>
</div>
<div
style={{
width: "21px",
height: "14px",
fontSize: "12px",
fontFamily: "SFUIDisplay-Regular, SFUIDisplay",
fontWeight: "400",
color: "#222222",
marginTop: "3px",
marginRight: "2px",
lineHeight: "14px",
padding: "8px 9px 2px 2px",
}}
>
{timeEvent(durationStr) + 1}"
</div>
</div>
</div>
);
}
}
export default AudioItem;
使用
import AudioItem from "../../components/AudioItem/audioItem";
<AudioItem src={"音频地址"} />;