我正在学习 Javascript 对象,我的代码有一个非常奇怪的问题。下面的代码使用
setInterval()
使时钟的时、分、秒臂根据系统时间移动。我添加了一个开始和停止按钮来启动/停止时钟。但是当我在 runClock()
中运行 interval
时,它无法按预期工作。
当我将代码放在
setInterval
内部的匿名函数中时,效果很好,就像setInterval(function(){ ... },1000)
一样。
const HOURHAND = document.querySelector("#hour");
const MINUTEHAND = document.querySelector("#minute");
const SECONDHAND = document.querySelector("#second");
function TimerInit(){
this.timer = null;
this.startBtn = document.querySelector('#startBtn');
this.stopBtn = document.querySelector('#stopBtn');
this.init = function(){
const dt = new Date();
console.log(`Hours: ${dt.getHours()} min: ${dt.getMinutes()} sec: ${dt.getSeconds()}`);
let hr = dt.getHours();
let min = dt.getMinutes();
let sec = dt.getSeconds();
let hourDeg = (hr * 360 / 12) + (min * (36/60) / 12);
let minDeg = (min * 360 / 60) + (sec * (36/60) / 60);
let secDeg = sec * 360 / 60;
return { hr:hourDeg, min:minDeg, sec:secDeg };
};
this.startBtn.onclick = function(){
let { hr, min, sec } = this.init();
console.log(`${hr} ${min} ${sec}`);
this.timer = setInterval(this.runClock.bind(this, hr, min, sec), 1000);
//the code below works
/*this.timer = setInterval(()=>{
hr += (3/360);
min += (6/60);
sec += 6;
console.log(`${hr} ${min} ${sec}`);
HOURHAND.style.transform = `rotate(${hr}deg)`;
MINUTEHAND.style.transform = `rotate(${min}deg)`;
SECONDHAND.style.transform = `rotate(${sec}deg)`;
},1000);*/
}.bind(this);
this.runClock = function(hr,min,sec){
hr += (3/360);
min += (6/60);
sec += 6;
//console.log(`${hr} ${min} ${sec}`);
HOURHAND.style.transform = `rotate(${hr}deg)`;
MINUTEHAND.style.transform = `rotate(${min}deg)`;
SECONDHAND.style.transform = `rotate(${sec}deg)`;
}
this.stopBtn.onclick = function(){
clearInterval(this.timer);
}.bind(this);
}
const obj = new TimerInit();
/* Layout */
.main {
display: flex;
padding: 2em;
height: 90vh;
justify-content: center;
align-items: middle;
}
.clockbox,
#clock {
width: 100%;
}
/* Clock styles */
.circle {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.mid-circle {
fill: #000;
}
.hour-marks {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.hour-arm {
fill: none;
stroke: #000;
stroke-width: 17;
stroke-miterlimit: 10;
}
.minute-arm {
fill: none;
stroke: #000;
stroke-width: 11;
stroke-miterlimit: 10;
}
.second-arm {
fill: none;
stroke: #000;
stroke-width: 4;
stroke-miterlimit: 10;
}
/* Transparent box ensuring arms center properly. */
.sizing-box {
fill: none;
}
/* Make all arms rotate around the same center point. */
/* Optional: Use transition for animation. */
#hour,
#minute,
#second {
transform-origin: 300px 300px;
transition: transform .5s ease-in-out;
}
<main class="main">
<div class="clockbox">
<svg id="clock" xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<g id="face">
<circle class="circle" cx="300" cy="300" r="253.9"/>
<path class="hour-marks" d="M300.5 94V61M506 300.5h32M300.5 506v33M94 300.5H60M411.3 107.8l7.9-13.8M493 190.2l13-7.4M492.1 411.4l16.5 9.5M411 492.3l8.9 15.3M189 492.3l-9.2 15.9M107.7 411L93 419.5M107.5 189.3l-17.1-9.9M188.1 108.2l-9-15.6"/>
<circle class="mid-circle" cx="300" cy="300" r="16.2"/>
</g>
<g id="hour">
<path class="hour-arm" d="M300.5 298V142"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="minute">
<path class="minute-arm" d="M300.5 298V67"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="second">
<path class="second-arm" d="M300.5 350V55"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
</svg>
</div><!-- .clockbox -->
</main>
<button id="startBtn">Start</button>
<button id="stopBtn">Stop</button>
有任何意见欢迎留言。
setInterval()
时,
this.runClock()
不起作用,因为每次通过 setInterval 调用它时,它都会收到相同的 hr
、min
和 sec
值。当这些值在函数内递增(以使时钟计时)时,它们不会保存在任何地方,因为函数执行时变量会丢失。然后,当再次调用该函数时,它再次收到与第一次运行时收到的相同的 hr
、min
和 sec
值。这样,时钟就不走了..
这是因为 runClock 不维护对象的状态。相反,您可以将这些值保存在对象的状态本身中,然后直接在
runClock()
中使用它们。这样,每次递增时,递增的值都会被保存。
const HOURHAND = document.querySelector("#hour");
const MINUTEHAND = document.querySelector("#minute");
const SECONDHAND = document.querySelector("#second");
function TimerInit(){
this.timer = null;
this.startBtn = document.querySelector('#startBtn');
this.stopBtn = document.querySelector('#stopBtn');
this.init = function(){
const dt = new Date();
console.log(`Hours: ${dt.getHours()} min: ${dt.getMinutes()} sec: ${dt.getSeconds()}`);
let hr = dt.getHours();
let min = dt.getMinutes();
let sec = dt.getSeconds();
this.hourDeg = (hr * 360 / 12) + (min * (36/60) / 12);
this.minDeg = (min * 360 / 60) + (sec * (36/60) / 60);
this.secDeg = sec * 360 / 60;
};
this.startBtn.onclick = function(){
this.init();
this.timer = setInterval(this.runClock.bind(this), 1000);
}.bind(this);
this.runClock = function(){
this.hourDeg += (3/360);
this.minDeg += (6/60);
this.secDeg += 6;
console.log(`${this.hourDeg} ${this.minDeg} ${this.secDeg}`);
HOURHAND.style.transform = `rotate(${this.hourDeg}deg)`;
MINUTEHAND.style.transform = `rotate(${this.minDeg}deg)`;
SECONDHAND.style.transform = `rotate(${this.secDeg}deg)`;
}
this.stopBtn.onclick = function(){
clearInterval(this.timer);
}.bind(this);
}
const obj = new TimerInit();
/* Layout */
.main {
display: flex;
padding: 2em;
height: 90vh;
justify-content: center;
align-items: middle;
}
.clockbox,
#clock {
width: 100%;
}
/* Clock styles */
.circle {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.mid-circle {
fill: #000;
}
.hour-marks {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.hour-arm {
fill: none;
stroke: #000;
stroke-width: 17;
stroke-miterlimit: 10;
}
.minute-arm {
fill: none;
stroke: #000;
stroke-width: 11;
stroke-miterlimit: 10;
}
.second-arm {
fill: none;
stroke: #000;
stroke-width: 4;
stroke-miterlimit: 10;
}
/* Transparent box ensuring arms center properly. */
.sizing-box {
fill: none;
}
/* Make all arms rotate around the same center point. */
/* Optional: Use transition for animation. */
#hour,
#minute,
#second {
transform-origin: 300px 300px;
transition: transform .5s ease-in-out;
}
<main class="main">
<div class="clockbox">
<svg id="clock" xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<g id="face">
<circle class="circle" cx="300" cy="300" r="253.9"/>
<path class="hour-marks" d="M300.5 94V61M506 300.5h32M300.5 506v33M94 300.5H60M411.3 107.8l7.9-13.8M493 190.2l13-7.4M492.1 411.4l16.5 9.5M411 492.3l8.9 15.3M189 492.3l-9.2 15.9M107.7 411L93 419.5M107.5 189.3l-17.1-9.9M188.1 108.2l-9-15.6"/>
<circle class="mid-circle" cx="300" cy="300" r="16.2"/>
</g>
<g id="hour">
<path class="hour-arm" d="M300.5 298V142"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="minute">
<path class="minute-arm" d="M300.5 298V67"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="second">
<path class="second-arm" d="M300.5 350V55"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
</svg>
</div><!-- .clockbox -->
</main>
<button id="startBtn">Start</button>
<button id="stopBtn">Stop</button>
const HOURHAND = document.querySelector("#hour");
const MINUTEHAND = document.querySelector("#minute");
const SECONDHAND = document.querySelector("#second");
function TimerInit(){
this.timer = null;
this.startBtn = document.querySelector('#startBtn');
this.stopBtn = document.querySelector('#stopBtn');
this.init = function(){
const dt = new Date();
console.log(`Hours: ${dt.getHours()} min: ${dt.getMinutes()} sec: ${dt.getSeconds()}`);
let hr = dt.getHours();
let min = dt.getMinutes();
let sec = dt.getSeconds();
this.hourDeg = (hr * 360 / 12) + (min * (36/60) / 12);
this.minDeg = (min * 360 / 60) + (sec * (36/60) / 60);
this.secDeg = sec * 360 / 60;
};
this.startBtn.onclick = function(){
this.init();
this.timer = setInterval(this.runClock.bind(this), 1000);
}.bind(this);
this.runClock = function(){
this.hourDeg += (3/360);
this.minDeg += (6/60);
this.secDeg += 6;
console.log(`${this.hourDeg} ${this.minDeg} ${this.secDeg}`);
HOURHAND.style.transform = `rotate(${this.hourDeg}deg)`;
MINUTEHAND.style.transform = `rotate(${this.minDeg}deg)`;
SECONDHAND.style.transform = `rotate(${this.secDeg}deg)`;
}
this.stopBtn.onclick = function(){
clearInterval(this.timer);
}.bind(this);
}
const obj = new TimerInit();
/* Layout */
.main {
display: flex;
padding: 2em;
height: 90vh;
justify-content: center;
align-items: middle;
}
.clockbox,
#clock {
width: 100%;
}
/* Clock styles */
.circle {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.mid-circle {
fill: #000;
}
.hour-marks {
fill: none;
stroke: #000;
stroke-width: 9;
stroke-miterlimit: 10;
}
.hour-arm {
fill: none;
stroke: #000;
stroke-width: 17;
stroke-miterlimit: 10;
}
.minute-arm {
fill: none;
stroke: #000;
stroke-width: 11;
stroke-miterlimit: 10;
}
.second-arm {
fill: none;
stroke: #000;
stroke-width: 4;
stroke-miterlimit: 10;
}
/* Transparent box ensuring arms center properly. */
.sizing-box {
fill: none;
}
/* Make all arms rotate around the same center point. */
/* Optional: Use transition for animation. */
#hour,
#minute,
#second {
transform-origin: 300px 300px;
transition: transform .5s ease-in-out;
}
<main class="main">
<div class="clockbox">
<svg id="clock" xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<g id="face">
<circle class="circle" cx="300" cy="300" r="253.9"/>
<path class="hour-marks" d="M300.5 94V61M506 300.5h32M300.5 506v33M94 300.5H60M411.3 107.8l7.9-13.8M493 190.2l13-7.4M492.1 411.4l16.5 9.5M411 492.3l8.9 15.3M189 492.3l-9.2 15.9M107.7 411L93 419.5M107.5 189.3l-17.1-9.9M188.1 108.2l-9-15.6"/>
<circle class="mid-circle" cx="300" cy="300" r="16.2"/>
</g>
<g id="hour">
<path class="hour-arm" d="M300.5 298V142"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="minute">
<path class="minute-arm" d="M300.5 298V67"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
<g id="second">
<path class="second-arm" d="M300.5 350V55"/>
<circle class="sizing-box" cx="300" cy="300" r="253.9"/>
</g>
</svg>
</div><!-- .clockbox -->
</main>
<button id="startBtn">Start</button>
<button id="stopBtn">Stop</button>