如何解决音频无法在 localhost 上播放,但在 codepen
我在 freeCodeCamp 上写了一个 25 + 5 时钟作为项目。它在可待因上运行良好,并按应有的方式播放音频。但是,当我尝试在 create-react-app 上本地播放它时,我使音频在计时器归零时不播放。我决定使用 onClick 测试音频,然后它就可以工作了。我认为它必须与在 useEffect 期间调用它的事实有关,但我不确定。任何帮助表示赞赏!
计时器归零后出现的错误是这个。
× 类型错误:试图分配给只读属性。 播放声音 src/index.js:115
112 | function playSound() {
113 | const audio = document.getElementById("beep");
114 | audio.removeAttribute("readonly");
> 115 | audio.duration = 1; // Need to pass first audio test
| ^ 116 | audio.play();
117 | }
118 | return (
这里是代码给大家看看。
import React,{ useState } from "react";
import ReactDOM from "react-dom";
import "./index.css";
function Timer() {
const [breakLength,setBreakLength] = useState(5);
const [sessionLength,setSessionLength] = useState(25);
const [timer,setTimer] = useState(1500); // 1500 is 25 minutes,but in seconds
const [timerType,setTimerType] = useState("session");
const [timerState,setTimerState] = useState("stopped");
const [timeoutId,setTimeoutId] = useState("");
React.useEffect(() => {
// If timer is > 0 and the timerState is clicked to running
if (timer > 0 && timerState === "running") {
setTimeoutId(setTimeout(() => setTimer(timer - 1),1000)); // Must use setTimeout as it only triggers expression once. setInterval will continuously call expression until told otherwise.
}
// If session timer ends.
else if (timer === 0 && timerType === "session") {
setTimerType("break"); // Change timer type back to break
setTimer(breakLength * 60); // Multiply by 60 because we need to convert minutes into seconds
playSound();
}
// If break timer ends
else if (timer === 0 && timerType === "break") {
setTimerType("session"); // Change timer type break
setTimer(sessionLength * 60); // Multiply by 60 because we need to convert minutes into seconds
playSound();
}
clearTimeout(timeoutId);
},[timer,timerState,timerType,breakLength,sessionLength]);
function resetClick() {
// simply reset all states and audio must be paused then set back to beginning with currentTime = 0
setTimerState("stopped");
setBreakLength(5);
setSessionLength(25);
setTimerType("session");
setTimer(1500);
const audio = document.getElementById("beep");
audio.pause();
audio.currentTime = 0;
}
function decrementBreakClick() {
// Doesn't let break length go below 1 and timer must be stopped
if (breakLength > 1 && timerState === "stopped") {
setBreakLength(breakLength - 1);
}
}
function incrementBreakClick() {
// Doesn't let break length go above 60 and timer must be stopped
if (breakLength < 60 && timerState === "stopped") {
setBreakLength(breakLength + 1);
}
}
function decrementSessionClick() {
// Doesn't let session length go below 1 and timer must be stopped
if (sessionLength > 1 && timerState === "stopped") {
setSessionLength(sessionLength - 1);
setTimer(timer - 60); // Take away 60 as timer is set in seconds.
}
}
function incrementSessionClick() {
// Doesn't let session length go below 1 and timer must be stopped
if (sessionLength < 60 && timerState === "stopped") {
setSessionLength(sessionLength + 1);
setTimer(timer + 60); // Add 60 as timer is set in seconds.
}
}
function startStopClick() {
// if state is stopped then change it to running. Else change running back to stopped
if (timerState === "stopped") {
setTimerState("running");
} else {
setTimerState("stopped");
}
}
// Convert the timer state that is in seconds to minutes and seconds.
function timerToClock() {
let minutes = Math.floor(timer / 60);
let seconds = timer - minutes * 60;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
return minutes + ":" + seconds;
}
function playSound() {
const audio = document.getElementById("beep");
audio.removeAttribute("readonly");
audio.duration = 1; // Need to pass first audio test
audio.play();
}
return (
<div>
<h1 id="header">25 + 5 Clock</h1>
<div id="machine-container">
<div id="break-session-containter">
<BreakLength
breakLength={breakLength}
decrement={decrementBreakClick}
increment={incrementBreakClick}
/>
<SessionLength
decrement={decrementSessionClick}
increment={incrementSessionClick}
sessionLength={sessionLength}
/>
</div>
<div id="timer-container">
<div id="timer-div">
<h2 id="timer-label">{timerType}</h2>
{/*Calling a function so need to add () */}
<span id="time-left">{timerToClock()}</span>
</div>
</div>
<div id="timer-controls-container">
<button id="start_stop" onClick={startStopClick}>
<i className="fa fa-play"></i>
<i className="fa fa-pause"></i>
</button>
<button id="reset" onClick={resetClick}>
<i className="fa fa-sync"></i>
</button>
<audio
id="beep"
src="https://raw.githubusercontent.com/freeCodeCamp/cdn/master/build/testable-projects-fcc/audio/BeepSound.wav"
></audio>
</div>
<div id="credit-container">
Designed and coded by:
<br />
<a
href="https://codepen.io/your-work/"
target="_blank"
rel="noreferrer"
>
Hunter Lacefield
</a>
</div>
</div>
</div>
);
}
function BreakLength(props) {
return (
<div id="break-length-container">
<h3 id="break-label">Break Length</h3>
<button
id="break-decrement"
className="down-button"
onClick={props.decrement}
>
<i className="fa fa-arrow-down"></i>
</button>
<span id="break-length" className="break-session-number">
{props.breakLength}
</span>
<button
id="break-increment"
className="up-button"
onClick={props.increment}
>
<i className="fa fa-arrow-up"></i>
</button>
</div>
);
}
function SessionLength(props) {
return (
<div id="session-length-container">
<h3 id="session-label">Session Length</h3>
<button
id="session-decrement"
className="down-button"
onClick={props.decrement}
>
<i className="fa fa-arrow-down"></i>
</button>
<span id="session-length" className="break-session-number">
{props.sessionLength}
</span>
<button
id="session-increment"
className="up-button"
onClick={props.increment}
>
<i className="fa fa-arrow-up"></i>
</button>
</div>
);
}
ReactDOM.render(<Timer />,document.getElementById("root"));
解决方法
我认为问题在于你clearTimeout
一开始就启动它。
React.useEffect(() => {
let timeoutId;
// If timer is > 0 and the timerState is clicked to running
if (timer > 0 && timerState === "running") {
timeoutId= setTimeout(() => setTimer(timer - 1),1000);
// Must use setTimeout as it only triggers expression once. setInterval will continuously call expression until told otherwise.
}
// If session timer ends.
else if (timer === 0 && timerType === "session") {
setTimerType("break"); // Change timer type back to break
setTimer(breakLength * 60); // Multiply by 60 because we need to convert minutes into seconds
playSound();
}
// If break timer ends
else if (timer === 0 && timerType === "break") {
setTimerType("session"); // Change timer type break
setTimer(sessionLength * 60); // Multiply by 60 because we need to convert minutes into seconds
playSound();
}
// This must be the clean-up function
() => {
if(timeoutId)
clearTimeout(timeoutId);
}
},[....]
如果您在其他任何地方使用 timeoutId
,您还可以将其设置为状态。否则,不需要状态。
希望有效!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。