0

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

欢迎任何意见。

4

1 回答 1

0

setInterval()调用命名函数时不起作用,this.runClock()因为每次 setInterval 调用它时,它都会收到相同的hrmin和值sec。当这些值在函数内部递增(以使时钟滴答作响)时,它们将无处保存,因为在函数执行时变量会丢失。hr然后当再次调用该函数时,它再次接收到与第一次运行时接收到的相同的minsec。这样,时钟不工作..

这是因为 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>

于 2020-10-10T14:51:21.840 回答