1. import Audio from "./AudioPlay";
    2. <Audio
    3. src={
    4. "https://xxx.mp3"
    5. }
    6. id={123}
    7. />
    1. import React, {Component} from 'react';
    2. import {Popover} from 'antd';
    3. import moment from 'moment';
    4. import style from './style.less';
    5. import playAudio from '../../../images/player.png';
    6. import pauseAudio from '../../../images/icon_play_stop.png';
    7. import onMuteAudio from '../../../images/mute.png';
    8. import onNoMuteAudio from '../../../images/no-mute.png';
    9. import download from '../../../images/download.png';
    10. class index extends Component {
    11. constructor(props) {
    12. super(props);
    13. this.state = {
    14. rateList: [1.0, 1.25, 1.5, 2.0],
    15. playRate: 1.0,
    16. isPlay: false,
    17. isMuted: false,
    18. volume: 100,
    19. allTime: 0,
    20. currentTime: 0
    21. };
    22. }
    23. componentDidMount() {}
    24. formatSecond(time) {
    25. const second = Math.floor(time % 60);
    26. const minite = Math.floor(time / 60);
    27. return `${minite}:${second >= 10 ? second : `0${second}`}`;
    28. }
    29. handleDownloadClick = () => {
    30. if (!this.props.src) return;
    31. const url = this.props.src;
    32. let request;
    33. const ishttps = document.location.protocol == 'https:';
    34. if (ishttps && url) {
    35. url.split('://');
    36. request = `https://${url.split('://')[1]}`;
    37. } else {
    38. request = url;
    39. }
    40. const text = `${this.props.DownloadName}.wav`;
    41. this.courseDownload(request, text);
    42. };
    43. // 实现js下载文件修改文件名失效问题 start
    44. courseDownload = (url, filename) => {
    45. const that = this;
    46. this.getBlob(url, function (blob) {
    47. that.saveAs(blob, filename);
    48. });
    49. };
    50. getBlob = (url, cb) => {
    51. const xhr = new XMLHttpRequest();
    52. xhr.open('GET', url, true);
    53. xhr.responseType = 'blob';
    54. xhr.onload = function () {
    55. if (xhr.status === 200) {
    56. cb(xhr.response);
    57. }
    58. };
    59. xhr.send();
    60. };
    61. /**
    62. * 保存
    63. * @param {Blob} blob
    64. * @param {String} filename 想要保存的文件名称
    65. */
    66. saveAs = (blob, filename) => {
    67. if (window.navigator.msSaveOrOpenBlob) {
    68. navigator.msSaveBlob(blob, filename);
    69. } else {
    70. const link = document.createElement('a');
    71. const body = document.querySelector('body');
    72. link.href = window.URL.createObjectURL(blob);
    73. link.download = filename;
    74. // fix Firefox
    75. link.style.display = 'none';
    76. body.appendChild(link);
    77. link.click();
    78. body.removeChild(link);
    79. window.URL.revokeObjectURL(link.href);
    80. }
    81. };
    82. // 该视频已准备好开始播放
    83. onCanPlay = () => {
    84. const {id} = this.props;
    85. const audio = document.getElementById(`audio${id}`);
    86. this.setState({
    87. allTime: audio.duration
    88. });
    89. };
    90. playAudio = () => {
    91. const {id} = this.props;
    92. const audio = document.getElementById(`audio${id}`);
    93. audio.play();
    94. this.setState({
    95. isPlay: true
    96. });
    97. };
    98. pauseAudio = () => {
    99. const {id} = this.props;
    100. const audio = document.getElementById(`audio${id}`);
    101. audio.pause();
    102. this.setState({
    103. isPlay: false
    104. });
    105. };
    106. onMuteAudio = () => {
    107. const {id} = this.props;
    108. const audio = document.getElementById(`audio${id}`);
    109. this.setState({
    110. isMuted: !audio.muted
    111. });
    112. audio.muted = !audio.muted;
    113. };
    114. changeTime = e => {
    115. const {value} = e.target;
    116. const {id} = this.props;
    117. const audio = document.getElementById(`audio${id}`);
    118. this.setState({
    119. currentTime: value
    120. });
    121. audio.currentTime = value;
    122. if (value === audio.duration) {
    123. this.setState({
    124. isPlay: false
    125. });
    126. }
    127. };
    128. // 当前播放位置改变时执行
    129. onTimeUpdate = () => {
    130. const {id} = this.props;
    131. const audio = document.getElementById(`audio${id}`);
    132. this.setState({
    133. currentTime: audio.currentTime
    134. });
    135. if (audio.currentTime === audio.duration) {
    136. this.setState({
    137. isPlay: false
    138. });
    139. }
    140. const progressTime = (100 * this.state.currentTime) / audio.duration;
    141. this.inputDom.style.background = `linear-gradient(to right, #007cef 0%, #007cef ${parseInt(progressTime, 10)}%, transparent ${parseInt(progressTime, 10)}%, transparent 100%)`;
    142. if (audio.currentTime === audio.duration) {
    143. this.setState({
    144. isPlay: false
    145. });
    146. this.inputDom.style.background = `linear-gradient(to right, #007cef 0%, #007cef 100%, transparent 100%, transparent 100%)`;
    147. }
    148. };
    149. changeVolume = e => {
    150. const {value} = e.target;
    151. const {id} = this.props;
    152. const audio = document.getElementById(`audio${id}`);
    153. audio.volume = value / 100;
    154. this.setState({
    155. volume: value,
    156. isMuted: !value
    157. });
    158. };
    159. // 倍速播放
    160. changePlayRate = num => {
    161. this.audioDom.playbackRate = num;
    162. this.setState({
    163. playRate: num
    164. });
    165. };
    166. render() {
    167. const {src, id} = this.props;
    168. // const {isPlay, isMuted, volume, allTime, currentTime, rateList, playRate} = this.state;//倍数
    169. const {isPlay, isMuted, volume, allTime, currentTime} = this.state;
    170. return (
    171. <div className={style.AudioComponent}>
    172. <audio
    173. id={`audio${id}`}
    174. src={src}
    175. ref={audio => {
    176. this.audioDom = audio;
    177. }}
    178. preload={'auto'}
    179. onCanPlay={this.onCanPlay}
    180. onTimeUpdate={this.onTimeUpdate}>
    181. <track src={src} kind="captions" />
    182. </audio>
    183. {isPlay ? (
    184. <div className={style.isPlayBox} onClick={this.pauseAudio}>
    185. <img src={pauseAudio} />
    186. </div>
    187. ) : (
    188. <div className={style.isPlayBox} onClick={this.playAudio}>
    189. <img src={playAudio} />
    190. </div>
    191. )}
    192. <div className={style.audioInputBox}>
    193. <div className={style.AudioBox}>
    194. <input className={style.AudioInput} ref={dom => (this.inputDom = dom)} type="range" step="0.01" max={allTime} value={currentTime} onChange={this.changeTime} />
    195. </div>
    196. <span className={style.timeBox}>{`${this.formatSecond(currentTime)}/${this.formatSecond(allTime)}`}</span>
    197. </div>
    198. <div className={style.volumeBox}>
    199. <Popover
    200. overlayClassName={'volumeBox'}
    201. trigger="click"
    202. content={
    203. <div className="volume">
    204. <div onClick={this.onMuteAudio}>
    205. <img src={!isMuted ? onMuteAudio : onNoMuteAudio} />
    206. </div>
    207. <input type="range" onChange={this.changeVolume} value={isMuted ? 0 : volume} />
    208. </div>
    209. }>
    210. <span>
    211. <img src={onNoMuteAudio} />
    212. </span>
    213. </Popover>
    214. </div>
    215. <div onClick={this.handleDownloadClick}>
    216. <img src={download} alt="" />
    217. </div>
    218. {/* <div>
    219. <span>倍速播放:</span>
    220. {rateList &&
    221. rateList.length > 0 &&
    222. rateList.map(item => (
    223. <button
    224. key={item}
    225. style={
    226. playRate === item
    227. ? {
    228. border: '1px solid #188eff',
    229. color: '#188eff'
    230. }
    231. : null
    232. }
    233. onClick={() => this.changePlayRate(item)}>
    234. {item}
    235. </button>
    236. ))}
    237. </div> */}
    238. </div>
    239. );
    240. }
    241. }
    242. export default index;
    1. .AudioComponent {
    2. display: flex;
    3. align-items: center;
    4. background-color: #fff;
    5. width: 100%;
    6. max-width: 500px;
    7. height: 32px;
    8. padding: 20px;
    9. border-radius: 16px;
    10. > div {
    11. margin-right: 12px;
    12. &:last-child {
    13. margin-right: 0;
    14. }
    15. }
    16. .content {
    17. display: flex;
    18. justify-content: center;
    19. align-items: center;
    20. }
    21. .timeBox {
    22. font-size: 12px;
    23. font-weight: 400;
    24. color: #bababa;
    25. margin-left: 4px;
    26. }
    27. .isPlayBox {
    28. img {
    29. width: 20px;
    30. height: 20px;
    31. .content;
    32. }
    33. }
    34. .audioInputBox {
    35. display: flex;
    36. align-items: center;
    37. }
    38. .AudioBox {
    39. background-color: #dfdfdf;
    40. position: relative;
    41. height: 8px;
    42. border-radius: 4px;
    43. overflow: hidden;
    44. width: 200px;
    45. .AudioInput {
    46. position: absolute;
    47. top: 0;
    48. left: 0;
    49. width: 100%;
    50. background: linear-gradient(to right, #007cef, transparent 0%, transparent);
    51. background-size: 100% 100%;
    52. &[type='range'] {
    53. width: 100%;
    54. -webkit-appearance: none;
    55. height: 8px;
    56. border-radius: 4px;
    57. background: -webkit-linear-gradient(#007cef, #007cef) no-repeat transparent;
    58. background-size: 0% 100%; /* 因为周期默认value=0.50正好占50% */
    59. }
    60. &[type='range']::-webkit-slider-thumb:hover {
    61. background-color: transparent;
    62. }
    63. &[type='range']::-webkit-slider-runnable-track {
    64. border-radius: 10px; /*将轨道设为圆角的*/
    65. }
    66. &[type='range']::-webkit-slider-thumb {
    67. position: relative;
    68. left: -16px;
    69. -webkit-appearance: none;
    70. background-color: #007cef;
    71. width: 16px;
    72. height: 8px;
    73. cursor: pointer;
    74. }
    75. }
    76. }
    77. }
    78. :global {
    79. .volumeBox {
    80. // transform: rotate(-90deg);
    81. // .ant-popover-arrow-content {
    82. // display: none;
    83. // }
    84. .ant-popover-inner-content {
    85. padding: 0 16px;
    86. }
    87. .volume {
    88. display: flex;
    89. > div {
    90. padding: 5px;
    91. }
    92. }
    93. }
    94. }