@nutui/nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
162 lines (161 loc) • 7 kB
JavaScript
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
};