UNPKG

@nutui/nutui-react-taro

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

162 lines (161 loc) 7 kB
import { _ as __rest } from "./tslib.es6-iWu3F_1J.js"; import React__default, { useState, useRef } from "react"; import { createInnerAudioContext } from "@tarojs/taro"; import { Service } from "@nutui/icons-react-taro"; import { R as Range } from "./range.taro-C5SuX_2b.js"; import { B as Button } from "./button.taro-CixO32Hw.js"; import { u as useConfig } from "./configprovider.taro-DpK4IiCE.js"; import { C as ComponentDefaults } from "./typings-DV9RBfhj.js"; const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { className: "", url: "", style: {}, autoplay: false, loop: false, type: "progress", onFastBack: (ctx) => { }, onForward: (ctx) => { }, onPause: (ctx) => { }, onPlay: (ctx) => { }, onPlayEnd: (ctx) => { }, onCanPlay: (ctx) => { } }); const Audio = (props) => { const classPrefix = "nut-audio"; const { locale } = useConfig(); const _a = Object.assign(Object.assign({}, defaultProps), props), { className, url, style, autoplay, loop, type, onFastBack, onForward, onPause, onPlay, onPlayEnd, onCanPlay, children, iconClassPrefix, iconFontClassName } = _a, rest = __rest(_a, ["className", "url", "style", "autoplay", "loop", "type", "onFastBack", "onForward", "onPause", "onPlay", "onPlayEnd", "onCanPlay", "children", "iconClassPrefix", "iconFontClassName"]); const [playing, setPlaying] = useState(false); const [totalSeconds, setTotalSeconds] = useState(0); const [percent, setPercent] = useState(0); const [isCanPlay, setIsCanPlay] = useState(false); const [currentDuration, setCurrentDuration] = useState("00:00:00"); const statusRef = useRef({ currentTime: 0, currentDuration: "00:00:00", percent: 0 }); const audioRef = useRef(createInnerAudioContext()); const audioCtx = audioRef.current; audioCtx.src = url; audioCtx.autoplay = autoplay || false; audioCtx.loop = loop || false; audioCtx.onPause(() => { onPause === null || onPause === void 0 ? void 0 : onPause(audioCtx); }); audioCtx.onEnded(() => { if (loop) { console.warn(locale.audio.tips || "onPlayEnd事件在loop=false时才会触发"); } else { onPlayEnd === null || onPlayEnd === void 0 ? void 0 : onPlayEnd(audioCtx); } }); audioCtx.onPlay(() => { const { duration } = audioCtx; setTotalSeconds(Math.floor(duration)); onPlay === null || onPlay === void 0 ? void 0 : onPlay(audioCtx); }); audioCtx.onCanplay(() => { const intervalID = setInterval(() => { if (audioCtx.duration !== 0) { setTotalSeconds(audioCtx.duration); clearInterval(intervalID); } }, 500); setIsCanPlay(true); onCanPlay === null || onCanPlay === void 0 ? void 0 : onCanPlay(audioCtx); }); audioCtx.onTimeUpdate(() => { const time = parseInt(`${audioCtx.currentTime}`); const formated = formatSeconds(`${time}`); statusRef.current.currentDuration = formated; setPercent(time / totalSeconds * 100); setCurrentDuration(formatSeconds(audioCtx.currentTime.toString())); }); audioCtx.onError((res) => { console.warn("onError", res.errCode, res.errMsg); }); function formatSeconds(value) { if (!value) { return "00:00:00"; } const time = parseInt(value); const hours = Math.floor(time / 3600); const minutes = Math.floor((time - hours * 3600) / 60); const secondss = time - hours * 3600 - minutes * 60; let result = ""; result += `${`0${hours.toString()}`.slice(-2)}:`; result += `${`0${minutes.toString()}`.slice(-2)}:`; result += `0${secondss.toString()}`.slice(-2); return result; } const handleBack = () => { const currentTime = Math.floor(audioCtx.currentTime); statusRef.current.currentTime = Math.max(currentTime - 1, 0); setCurrentDuration(formatSeconds(statusRef.current.currentTime.toString())); audioCtx.seek(statusRef.current.currentTime); onFastBack === null || onFastBack === void 0 ? void 0 : onFastBack(audioCtx); }; const handleForward = () => { const currentTime = Math.floor(audioCtx.currentTime); statusRef.current.currentTime = Math.min(currentTime + 1, audioCtx.duration); setCurrentDuration(formatSeconds(statusRef.current.currentTime.toString())); audioCtx.seek(statusRef.current.currentTime); onForward === null || onForward === void 0 ? void 0 : onForward(audioCtx); }; const handleStatusChange = () => { setPlaying(!playing); if (!playing) { audioCtx.play(); } else { audioCtx.pause(); } }; const renderIcon = () => { return React__default.createElement( "div", { className: `${classPrefix}-icon` }, React__default.createElement( "div", { className: `${classPrefix}-icon-box} ${playing ? `${classPrefix}-icon-play}` : `${classPrefix}-icon-stop}`}`, onClick: handleStatusChange }, React__default.createElement(Service, { className: playing ? "nut-icon-loading" : "" }) ) ); }; const renderProgerss = () => { return React__default.createElement( React__default.Fragment, null, React__default.createElement( "div", { className: `${classPrefix}-progress` }, React__default.createElement("div", { className: "time" }, currentDuration), React__default.createElement( "div", { className: `${classPrefix}-progress-bar-wrapper` }, React__default.createElement(Range, { value: percent, onChange: (val) => setPercent(val), currentDescription: null, maxDescription: null, minDescription: null, "inactive-color": "#cccccc", "active-color": "#fa2c19" }) ), React__default.createElement("div", { className: "time" }, formatSeconds(`${totalSeconds}`) || "00:00:00") ), React__default.createElement( "div", { className: isCanPlay ? "custom-button-group" : "custom-button-group-disable" }, React__default.createElement(Button, { type: "primary", size: "small", className: "back", onClick: handleBack }, locale.audio.back || "快退"), React__default.createElement(Button, { type: "primary", size: "small", className: "start", onClick: handleStatusChange }, playing ? `${locale.audio.pause || "暂停"}` : `${locale.audio.start || "开始"}`), React__default.createElement(Button, { type: "primary", size: "small", onClick: handleForward }, locale.audio.forward || "快进") ) ); }; const renderNone = () => { return React__default.createElement("div", { className: `${classPrefix}-none-container`, onClick: handleStatusChange }, children); }; const renderAudio = () => { switch (type) { case "icon": return renderIcon(); case "progress": return renderProgerss(); case "none": return renderNone(); default: return null; } }; return React__default.createElement("div", Object.assign({ className: `${classPrefix} ${className}`, style }, rest), renderAudio()); }; Audio.displayName = "NutAudio"; export { Audio as A };