import Audio from "./AudioPlay"; <Audio src={ "https://xxx.mp3" } id={123}/>
import React, {Component} from 'react';import {Popover} from 'antd';import moment from 'moment';import style from './style.less';import playAudio from '../../../images/player.png';import pauseAudio from '../../../images/icon_play_stop.png';import onMuteAudio from '../../../images/mute.png';import onNoMuteAudio from '../../../images/no-mute.png';import download from '../../../images/download.png';class index extends Component { constructor(props) { super(props); this.state = { rateList: [1.0, 1.25, 1.5, 2.0], playRate: 1.0, isPlay: false, isMuted: false, volume: 100, allTime: 0, currentTime: 0 }; } componentDidMount() {} formatSecond(time) { const second = Math.floor(time % 60); const minite = Math.floor(time / 60); return `${minite}:${second >= 10 ? second : `0${second}`}`; } handleDownloadClick = () => { if (!this.props.src) return; const url = this.props.src; let request; const ishttps = document.location.protocol == 'https:'; if (ishttps && url) { url.split('://'); request = `https://${url.split('://')[1]}`; } else { request = url; } const text = `${this.props.DownloadName}.wav`; this.courseDownload(request, text); }; // 实现js下载文件修改文件名失效问题 start courseDownload = (url, filename) => { const that = this; this.getBlob(url, function (blob) { that.saveAs(blob, filename); }); }; getBlob = (url, cb) => { const xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'blob'; xhr.onload = function () { if (xhr.status === 200) { cb(xhr.response); } }; xhr.send(); }; /** * 保存 * @param {Blob} blob * @param {String} filename 想要保存的文件名称 */ saveAs = (blob, filename) => { if (window.navigator.msSaveOrOpenBlob) { navigator.msSaveBlob(blob, filename); } else { const link = document.createElement('a'); const body = document.querySelector('body'); link.href = window.URL.createObjectURL(blob); link.download = filename; // fix Firefox link.style.display = 'none'; body.appendChild(link); link.click(); body.removeChild(link); window.URL.revokeObjectURL(link.href); } }; // 该视频已准备好开始播放 onCanPlay = () => { const {id} = this.props; const audio = document.getElementById(`audio${id}`); this.setState({ allTime: audio.duration }); }; playAudio = () => { const {id} = this.props; const audio = document.getElementById(`audio${id}`); audio.play(); this.setState({ isPlay: true }); }; pauseAudio = () => { const {id} = this.props; const audio = document.getElementById(`audio${id}`); audio.pause(); this.setState({ isPlay: false }); }; onMuteAudio = () => { const {id} = this.props; const audio = document.getElementById(`audio${id}`); this.setState({ isMuted: !audio.muted }); audio.muted = !audio.muted; }; changeTime = e => { const {value} = e.target; const {id} = this.props; const audio = document.getElementById(`audio${id}`); this.setState({ currentTime: value }); audio.currentTime = value; if (value === audio.duration) { this.setState({ isPlay: false }); } }; // 当前播放位置改变时执行 onTimeUpdate = () => { const {id} = this.props; const audio = document.getElementById(`audio${id}`); this.setState({ currentTime: audio.currentTime }); if (audio.currentTime === audio.duration) { this.setState({ isPlay: false }); } const progressTime = (100 * this.state.currentTime) / audio.duration; this.inputDom.style.background = `linear-gradient(to right, #007cef 0%, #007cef ${parseInt(progressTime, 10)}%, transparent ${parseInt(progressTime, 10)}%, transparent 100%)`; if (audio.currentTime === audio.duration) { this.setState({ isPlay: false }); this.inputDom.style.background = `linear-gradient(to right, #007cef 0%, #007cef 100%, transparent 100%, transparent 100%)`; } }; changeVolume = e => { const {value} = e.target; const {id} = this.props; const audio = document.getElementById(`audio${id}`); audio.volume = value / 100; this.setState({ volume: value, isMuted: !value }); }; // 倍速播放 changePlayRate = num => { this.audioDom.playbackRate = num; this.setState({ playRate: num }); }; render() { const {src, id} = this.props; // const {isPlay, isMuted, volume, allTime, currentTime, rateList, playRate} = this.state;//倍数 const {isPlay, isMuted, volume, allTime, currentTime} = this.state; return ( <div className={style.AudioComponent}> <audio id={`audio${id}`} src={src} ref={audio => { this.audioDom = audio; }} preload={'auto'} onCanPlay={this.onCanPlay} onTimeUpdate={this.onTimeUpdate}> <track src={src} kind="captions" /> </audio> {isPlay ? ( <div className={style.isPlayBox} onClick={this.pauseAudio}> <img src={pauseAudio} /> </div> ) : ( <div className={style.isPlayBox} onClick={this.playAudio}> <img src={playAudio} /> </div> )} <div className={style.audioInputBox}> <div className={style.AudioBox}> <input className={style.AudioInput} ref={dom => (this.inputDom = dom)} type="range" step="0.01" max={allTime} value={currentTime} onChange={this.changeTime} /> </div> <span className={style.timeBox}>{`${this.formatSecond(currentTime)}/${this.formatSecond(allTime)}`}</span> </div> <div className={style.volumeBox}> <Popover overlayClassName={'volumeBox'} trigger="click" content={ <div className="volume"> <div onClick={this.onMuteAudio}> <img src={!isMuted ? onMuteAudio : onNoMuteAudio} /> </div> <input type="range" onChange={this.changeVolume} value={isMuted ? 0 : volume} /> </div> }> <span> <img src={onNoMuteAudio} /> </span> </Popover> </div> <div onClick={this.handleDownloadClick}> <img src={download} alt="" /> </div> {/* <div> <span>倍速播放:</span> {rateList && rateList.length > 0 && rateList.map(item => ( <button key={item} style={ playRate === item ? { border: '1px solid #188eff', color: '#188eff' } : null } onClick={() => this.changePlayRate(item)}> {item} </button> ))} </div> */} </div> ); }}export default index;
.AudioComponent { display: flex; align-items: center; background-color: #fff; width: 100%; max-width: 500px; height: 32px; padding: 20px; border-radius: 16px; > div { margin-right: 12px; &:last-child { margin-right: 0; } } .content { display: flex; justify-content: center; align-items: center; } .timeBox { font-size: 12px; font-weight: 400; color: #bababa; margin-left: 4px; } .isPlayBox { img { width: 20px; height: 20px; .content; } } .audioInputBox { display: flex; align-items: center; } .AudioBox { background-color: #dfdfdf; position: relative; height: 8px; border-radius: 4px; overflow: hidden; width: 200px; .AudioInput { position: absolute; top: 0; left: 0; width: 100%; background: linear-gradient(to right, #007cef, transparent 0%, transparent); background-size: 100% 100%; &[type='range'] { width: 100%; -webkit-appearance: none; height: 8px; border-radius: 4px; background: -webkit-linear-gradient(#007cef, #007cef) no-repeat transparent; background-size: 0% 100%; /* 因为周期默认value=0.50正好占50% */ } &[type='range']::-webkit-slider-thumb:hover { background-color: transparent; } &[type='range']::-webkit-slider-runnable-track { border-radius: 10px; /*将轨道设为圆角的*/ } &[type='range']::-webkit-slider-thumb { position: relative; left: -16px; -webkit-appearance: none; background-color: #007cef; width: 16px; height: 8px; cursor: pointer; } } }}:global { .volumeBox { // transform: rotate(-90deg); // .ant-popover-arrow-content { // display: none; // } .ant-popover-inner-content { padding: 0 16px; } .volume { display: flex; > div { padding: 5px; } } }}