【问题标题】:How do I reference a variable for clearInterval in a different function?如何在不同的函数中引用 clearInterval 的变量?
【发布时间】:2020-07-17 18:41:29
【问题描述】:

我有一个圆形图像,我想通过单击按钮来旋转并通过单击不同的按钮来停止。

spin() 函数有效,但 stop() 无效,因为值在 spin() 函数之外消失(如果我错了,请纠正我)。我应该如何解决这个问题?我愿意使用相同的按钮来旋转和停止,但我的 if else 语句会产生相同的结果 - 旋转图像有效,但我无法停止。

另一个意外错误是,如果我多次单击旋转按钮,旋转会变得更快。

这是我的代码:

var spinImage;  
function spin(){

        spinImage = document.getElementById('spinImage'), degree = 0;
        setInterval(function() {
        spinImage.style.transform = "rotate(" + ++degree + "deg)";}, 1);
}

function stop(){
        clearInterval(spinImage);
}

我需要坚持使用纯 javascript 并使用 setInterval/clearInterval 方法。

【问题讨论】:

    标签: javascript


    【解决方案1】:

    你要找的值是setInterval的返回值:

    var intervalId;
    function spin() {
      var spinImage = document.getElementById('spinImage');
      var degree = 0;
      intervalId = setInterval(function() {
        spinImage.style.transform = 'rotate(' + ++degree + 'deg)';
      }, 1);
    }
    
    function stop() {
      clearInterval(intervalId);
    }
    
    

    【讨论】:

      【解决方案2】:

      你需要记住间隔id,这样你才能停止它。

      let intervalId = null;
      
      function spin() {
        spinImage = document.getElementById('spinImage'), degree = 0;
      
        intervalId = setInterval(function() {
          spinImage.style.transform = "rotate(" + ++degree + "deg)";
        }, 1);
      }
      
      function stop() {
        clearInterval(intervalId);
      }
      

      ES6 类

      您可以将此逻辑封装到可重用的类对象中,即ImageSpinner

      const main = () => {
        const spinner = new ImageSpinner('#spinImage');
      
        addEventListeners('.btn-toggle', 'click', (e) => {
          spinner.toggle();
          let attr = `data-text-${spinner.isRunning() ? 'off' : 'on'}`;
          e.currentTarget.textContent = e.currentTarget.getAttribute(attr);
        });
      
        addEventListeners('.btn-reset', 'click', (e) => {
          spinner.reset();
          let btn = document.querySelector('.btn-toggle');
          btn.textContent = btn.getAttribute('data-text-on');
        });
      }
      
      class ImageSpinner {
        constructor(selector, rate) {
          /* @protected */ this.image = document.querySelector(selector);
          /* @protected */ this.rate = rate;
          /* @private   */ this.__intervalId = null;
          /* @private   */ this.__degree = 0;
        }
        /* @public */ isRunning() {
          return this.__intervalId != null;
        }
        /* @public */ reset() {
          if (this.isRunning()) this.stop();
          this.__degree = 0;
          this.__rotate();
        }
        /* @public */ start() {
          if (!this.isRunning()) {
            this.__intervalId = setInterval(() => { this.update() }, this.rate);
          } else {
            console.log('Already running...');
          }
        }
        /* @public */ stop() {
          if (this.isRunning()) {
            clearInterval(this.__intervalId);
            this.__intervalId = null;
          } else {
            console.log('Not currently running...');
          }
        }
        /* @public */ toggle() {
          this.isRunning() ? this.stop() : this.start();
        }
        /* @protected */ update() {
          this.__degree = (this.__degree + 1) % 360;
          this.__rotate();
        }
        /* @private */ __rotate() {
          this.image.style.transform = "rotate(" + this.__degree + "deg)";
        }
      }
      
      /*
       * Can either be an object of event handlers,
       * or an event name followed by a function.
       */
      function addEventListeners(elementsOrSelector, events) {
        ((els) => els.forEach(el => 
          (typeof events === 'string' && arguments.length > 2)
            ? el.addEventListener(arguments[1], arguments[2])
            : Object.keys(events)
              .forEach(name => el.addEventListener(name, events[name]))))
        (Array.from((typeof elementsOrSelector === 'string')
          ? document.querySelectorAll(elementsOrSelector)
          : elementsOrSelector.entries
            ? elementsOrSelector
            : [elementsOrSelector]));
      }
      
      main(); // Execute main function
      body {
        background: #222;
        padding: 1.25em;
      }
      
      img {
        border: 2px dotted white;
        margin-left: 0.5em;
      }
      
      .btn-wrapper {
        margin-top: 1.75em;
      }
      
      .btn-toggle {
        display: inline-block;
        width: 64px;
        cursor: pointer;
      }
      <img id="spinImage" src="https://lh5.googleusercontent.com/-ajlbNdBMWwA/AAAAAAAAAAI/AAAAAAAAAAo/ND2LpoxaqAQ/photo.jpg?sz=96" alt="" width="96" height="96"/>
      <div class="btn-wrapper">
        <button class="btn btn-toggle" data-text-on="Start" data-text-off="Pause">Start</button>
        <button class="btn btn-reset">Reset</button>
      </div>

      【讨论】:

        【解决方案3】:

        初始化 setInterval 时需要获取id(此处存储在自旋变量中)。该变量将引用 setInterval 以便您可以使用 stop 函数清除它。

        另一个意外错误 (faster spinning on consecutive clicks) 是由于之前的 setInterval id 未被清除并创建了新的。所以,你点击的次数;你会有那么多 setIntervals。为避免这种情况,您需要清除现有的 id,然后使用新设置的间隔重新初始化。

        已修复代码。请看:

        var spinImage;
        var spin;  
        function spin(){
            spinImage = document.getElementById('spinImage');
            degree = 0;
            if(spin) stop();
            spin = setInterval(function() {
                spinImage.style.transform = "rotate(" + ++degree + "deg)";
            }, 1);
        }
        
        function stop(){
            clearInterval(spin);
        }
        

        希望对您有所帮助。回复任何疑问/澄清

        【讨论】:

          【解决方案4】:
          <!DOCTYPE html>
          
            <head>
              <title>Spin</title>
            </head>
            <body>
          
              <button id='spinStart'>Start</button>
              <button id='spinStop'>Stop</button>
          
              <script>
                var spinning = false;
                var handle;
                var counter = 0;
          
                // Add click event listener to the start button
                window.document.getElementById('spinStart').addEventListener("click", start);
                // Add click event listener to the stop button
                window.document.getElementById('spinStop').addEventListener("click", stop);
          
                function start() {
          
                  if(spinning === true) {
                    console.log('spinning already')
                    // Do nothing here as it's already spinning.
                    spinning = !spinning;
                  } 
          
                  if(spinning === false) {
                    // Not spinning here, so we have to init the setInterval
                    handle = setInterval(() => {
                      console.log(counter);
                      counter++;
                    }, 1000);
                    spinning = !spinning;
                  }
                }
          
                function stop() {
                  //We only want to stop the spinner if it's actually spinning
                  if(spinning === true){
                    console.log('clearing the interval now!');
                    clearInterval(handle);
                  }
                }
              </script>
            </body>
          </html>
          

          根据需要替换您的代码。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-03-16
            • 2020-04-05
            • 2019-02-06
            • 2020-01-02
            • 1970-01-01
            相关资源
            最近更新 更多