utils.js
// 时间格式转换
export const msToTime = (duration) => {
return moment.utc(duration).format('HH:mm:ss')
}
复制代码
自定义音频: 此组件原始音频标签由于业务需求将标签dom传入组件,需要自己举一反三将标签dom放入该组件。
import React, { useEffect, useState } from 'react';
import './styles.less';
import classNames from 'classnames';
import { msToTime } from './utils.js';
import { Icon, Slider, Menu, Dropdown } from 'antd';
const CustomizeAudio = (props) => {
const { audioDom } = props
const [duration, setDurention] = useState(0)
const [currentTime, setCurrentTime] = useState(0)
const [playIcon, setPlayIcon] = useState('play-circle')
const [sliderValue, setSliderValue] = useState(0)
const [clickPlayFlag, setClickPlayFlag] = useState(false)
useEffect(() => {
getDurationTime()
timeUpdate()
audioPlaying()
audioPause()
}, [])
// 获取总时长
const getDurationTime = () => {
audioDom.load()
audioDom.ondurationchange = () => {
setDurention(audioDom.duration)
}
}
// 音频开始播放
const audioPlaying = () => {
audioDom.onplaying = () => {
setPlayIcon('pause-circle')
}
}
// 音频播放时时间位置跟着变化
const timeUpdate = () => {
audioDom.ontimeupdate = () => {
// 初始总时长为NaN
if (audioDom.duration) {
setCurrentTime(audioDom.currentTime)
setSliderValue(parseInt((audioDom.currentTime / audioDom.duration) * 100))
if (audioDom.currentTime == audioDom.duration) {
setPlayIcon('play-circle')
}
}
}
}
// 音频暂停播放
const audioPause = () => {
audioDom.onpause = () => {
setPlayIcon('play-circle')
}
}
// 点击播放按钮
const clickPlayBtn = () => {
if (audioDom.paused) {
audioDom.currentTime = currentTime
audioDom.play()
setClickPlayFlag(true)
} else {
setClickPlayFlag(false)
audioDom.pause()
}
}
// 拖动滑块
const sliderChange = (value) => {
setSliderValue(value)
setPlayProgress(value)
}
// 设置播放进度
const setPlayProgress = (value) => {
const currentTime = value / 100 * audioDom.duration
audioDom.currentTime = currentTime
setCurrentTime(currentTime)
// 当前处于播放状态,需要暂停播放
if (!audioDom.paused) {
audioDom.pause()
}
}
// 滑块停止滑动后
const sliderAfterChange = () => {
// 判断滑块暂停后是否需要开启播放
clickPlayFlag && clickPlayBtn()
}
// 调整播放倍速
const [playSpeed, setPlaySpeed] = useState('1')
const adjustmentPlaySpeed = ({ key }) => {
setPlaySpeed(key)
audioDom.playbackRate = key
}
const menu = (
<Menu onClick={adjustmentPlaySpeed} selectedKeys={[playSpeed]}>
{['0.25', '0.5', '0.75', '1', '1.25', '1.5', '1.75', '2'].map(doubleSpeed => <Menu.Item key={doubleSpeed}>{doubleSpeed}</Menu.Item>)}
</Menu>
)
return (
<div className='audioContainer'>
<div className='playIcon'><Icon type={playIcon} theme="filled" onClick={() => clickPlayBtn()} /></div>
<div className={classNames('currentTime', 'time')}>{msToTime(currentTime * 1000)}</div>
<div className='progressBar'><Slider value={sliderValue} tooltipVisible={false} onChange={sliderChange} onAfterChange={sliderAfterChange} /></div>
<div className={classNames('duration', 'time')}>{msToTime(duration * 1000)}</div>
<Dropdown overlay={menu} placement="topLeft" trigger={['click']} overlayClassName='playSeedMenu' getPopupContainer={trigger => trigger.parentNode}>
<div className='multiple'>{playSpeed}x</div>
</Dropdown>
</div>
)
}
export default CustomizeAudio
复制代码
styles.less
.audioContainer {
display: flex;
align-items: center;
margin-bottom: 10px;
padding: 10px 25px;
border-radius: 35px;
background-color: #F1F3F4;
.playIcon {
margin-right: 26px;
cursor: pointer;
color: @primary-color;
font-size: 26px;
}
.time {
color: rgba(0, 0, 0, .85);
font-family: PingFangSC-Regular, PingFang SC;
font-size: 16px;
font-weight: 400;
line-height: 22px;
}
.currentTime {
margin-right: 12px;
}
.progressBar {
width: 373px;
margin-right: 12px;
.ant-slider .ant-slider-rail {
background-color: #E1E1E1;
}
}
.duration {
margin-right: 18px;
}
.multiple {
cursor: pointer;
color: #000000;
font-size: 12px;
&:hover {
color: @primary-color;
}
}
}
.playSeedMenu {
overflow-x: hidden;
overflow-y: auto;
width: 100px;
max-height: 150px;
}
复制代码