对象构造函数内的Javascript setInterval 无法按预期工作

问题描述 投票:0回答:2

我正在学习 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>

有任何意见欢迎留言。

javascript svg
2个回答
0
投票
当您调用命名函数

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>


0
投票

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>

© www.soinside.com 2019 - 2024. All rights reserved.