使用 React hooks 优雅解决 mp3 的播放 和 暂停
2021-05-13 12:12 muamaker 阅读(1184) 评论(0) 编辑 收藏 举报
在class 组件中,我们需要在 componentDidMounted 里面给 mp3 加上监听,然后在 组件销毁的时候 去掉监听。
来控制 mp3 的播放和暂停。相对来说比较麻烦。难以抽离。
这里用 hooks 达到完全抽离的效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | interface IAudioProps extends React.AudioHTMLAttributes<any> { src: string } const wrapEvent = (userEvent:any, proxyEvent?:any) => { return (event:any) => { try { proxyEvent && proxyEvent(event); } finally { userEvent && userEvent(event); } }; }; const useAudio = (props:IAudioProps)=>{ const ref = useRef< HTMLAudioElement | null >( null ) const [state,setState] = useState({ time: 0, duration: 0, paused: true , muted: false , volume: 1 }); const onPlay = ()=>{ setState((obj)=>{ return {...obj,paused: false } }) } const onPause = ()=>{ setState((obj)=>{ return {...obj,paused: true } }) } const element = React.createElement( "audio" ,{ ...props, ref, onPlay: wrapEvent(props.onPlay, onPlay), onPause: wrapEvent(props.onPause, onPause), onEnded: wrapEvent(props.onEnded, onPause), }) let lockPlay: boolean = false ; const controls = { play: () => { const el = ref.current; if (!el) { return undefined; } if (!lockPlay) { const promise = el.play(); const isPromise = typeof promise === 'object' ; if (isPromise) { lockPlay = true ; const resetLock = () => { lockPlay = false ; }; promise.then(resetLock, resetLock); } return promise; } return undefined; }, pause: () => { const el = ref.current; if (el && !lockPlay) { return el.pause(); } }, seek: (time: number) => { const el = ref.current; if (!el || state.duration === undefined) { return ; } time = Math.min(state.duration, Math.max(0, time)); el.currentTime = time; }, volume: (volume: number) => { const el = ref.current; if (!el) { return ; } volume = Math.min(1, Math.max(0, volume)); el.volume = volume; setState((obj)=>{ return {...obj,volume} }); }, mute: () => { const el = ref.current; if (!el) { return ; } el.muted = true ; }, unmute: () => { const el = ref.current; if (!el) { return ; } el.muted = false ; }, }; return [ <span> {element} { state.paused ? <button onClick={controls.play}>点击播放</button>:<button onClick={controls.pause}>点击暂停</button> } </span>, controls, ref ] as const } |
使用
1 2 3 4 5 6 7 8 | const TestState = ()=>{ const [audio,controls,ref] = useAudio({src: "http://cloud.chan3d.com/cdn/website/mp3/1.mp3" }) return ( <div className= "test-state" > {audio} </div> ) } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2019-05-13 怎样理解阻塞非阻塞与同步异步的区别? 并行和并发区别?线程与进程