在class 组件中,我们需要在 componentDidMounted 里面给 mp3 加上监听,然后在 组件销毁的时候 去掉监听。
来控制 mp3 的播放和暂停。相对来说比较麻烦。难以抽离。
这里用 hooks 达到完全抽离的效果:
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 }
使用
const TestState = ()=>{ const [audio,controls,ref] = useAudio({src:"http://cloud.chan3d.com/cdn/website/mp3/1.mp3"}) return ( <div className="test-state"> {audio} </div> ) }