如何防止JavaScript滚动动画中的变量重置?

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

我正在为进度条制作滚动动画。当滚动到达特定元素时,其宽度从 0 变化到 78%。但是,有一个问题:每当我再次以相同的高度滚动时,宽度就会重置。我知道发生这种情况是因为每次滚动时范围变量都会重新分配为 0,但我不确定如何修复它。我读过有关闭包的内容,但不知道如何将它们应用到我的代码中。感谢您的时间和帮助!

这是我的代码:

const SEORange = document.getElementById("SEO");



window.addEventListener("scroll", () => {
  let top = SEORange.getBoundingClientRect().top;
  let range = 0;
  // Define constants for readability
  const TARGET_WIDTH = 78;         // Target width percentage
  const INCREMENT_INTERVAL = 10;  //  width increment in milliseconds 
  const SCROLL_THRESHOLD = 0.905;// Start Scroll threshold animation
  const INCREMENT_STEP = 1;     // Step by which the width increases

  if (top < window.innerHeight * SCROLL_THRESHOLD) {
    const interval = setInterval(() => {
      if (range >= TARGET_WIDTH) {
        clearInterval(interval);
      } else {
        range += INCREMENT_STEP;
        SEORange.style.width = range + "%";
      }
    }, INCREMENT_INTERVAL);
  }
});
* {
  height: 100vh;  /* Added height to see what happens when scrolling */
}

#section2-text-container {
  justify-content: end;
  flex-basis: 50%;
  margin-top: 5%;
}

#section2-text-container form {
  margin-top: 10%;
}

.range-container {
  background-color: #000000;
  border-radius: 0 10px 10px 0;
  width: 90%;
  height: 8px;
  position: relative;
}

#section2-text-container input {
  appearance: none;
  -webkit-appearance: none;
  background-color: #64bfd2;
  width: 0;
  height: 4px;
  margin: 0 5% 0 0;
  position: absolute;
  inset: 0 0 0 0;
}

#section2-text-container input::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 0px;
  background: #010101;
  height: 0px;
}

#section2-text-container input::-moz-range-thumb {
  width: 0px;
  background: #04aa6d;
}
<!DOCTYPE html>
<html>
  <body>
    <div id="section2-text-container">
      <form>
        <label for="SEO">SEO</label><br><br>
        <div class="range-container">
          <input id="SEO" disabled type="range" value="0" />
        </div>
      </form>
    </div>
  </body>
</html>

问题

如何修改 JavaScript 代码以防止范围变量在每次滚动时重置?我非常感谢有关使用闭包或其他方法来解决此问题的任何指导。谢谢!

javascript
2个回答
1
投票

首先,您必须确保清除间隔,因为当用户滚动时,每秒会多次触发“scroll”事件。

const SEORange = document.getElementById("SEO");
let intervalId;
let range = 0;

window.addEventListener("scroll", () => {
  let top = SEORange.getBoundingClientRect().top;

  // If intervalId is set, it means the code has been ran once.
  if (top < window.innerHeight * 0.905 && !intervalId) {
    intervalId = setInterval(() => {
      if (range === 78) {
        clearInterval(intervalId);
      } else {
        range++;
        SEORange.style.width = range + "%";
      }
    }, 10);
  }
})

另一个解决方案是添加一个类来触发您想要的转换。在我看来,这比使用间隔设置宽度更好(更平滑)。

const SEORange2 = document.getElementById("SEO2");

window.addEventListener("scroll", () => {
  let top = SEORange.getBoundingClientRect().top;

  if (top < window.innerHeight * 0.905) {
    SEORange2.classList.add("animate");
  }
});
#SEO2 {
  height: 30px;
  width: 0;
  background-color: yellow;
  transition: width 780ms linear;
}

#SEO2.animate {
  width: 78%;
}

代码沙盒


0
投票

这里我尝试在一个代码块中包含 3 个元素。如果有人有更短的解决方案与我分享 通过帮助@c0m1t

const eagerToLearnRange = document.getElementById("eager-to-learn");
const frontEndRange = document.getElementById("front-end");
const SEORange = document.getElementById("SEO");


let intervalId;
window.addEventListener("scroll", () => {
  let top = SEORange.getBoundingClientRect().top;
  let range = 0;
  if (top < window.innerHeight * 0.905 && !intervalId) {
    intervalId = setInterval(() => {
      if (range <= 20) {
        range++;
        SEORange.style.width = range + "%";
        frontEndRange.style.width = range + "%";
        eagerToLearnRange.style.width = range + "%";
      } else if (65 >= range && range >= 20) {
        frontEndRange.style.width = range + "%";
        eagerToLearnRange.style.width = range + "%";
        range++;
      } else if (65 <= range && range <= 100) {
        eagerToLearnRange.style.width = range + "%";
        range++;
      } else if (range === 100) {
        clearInterval(intervalId);
      }
    }, 10);
  }
});
* { height:200vh /*add some height to show you effect */
}

#section2-text-container form {
  margin-top: 10%;
}
.range-container {
  background-color: #000000;
  border-radius: 0 10px 10px 0;
  width: 90%;
  height: 8px;
  position: relative;
}
#section2-text-container input {
  appearance: none;
  -webkit-appearance: none;
  background-color: #64bfd2;
  width: 0;
  height: 4px;
  margin: 0 5% 0 0;
  position: absolute;
  inset: 0 0 0 0;
}

#section2-text-container input::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 0px;
  height: 0px;
}
#section2-text-container input::-moz-range-thumb {
  width: 0px;
  height: 0px;

}
<DOCTYPE html>
<html>
<body>
  <div id="section2-text-container">
     <form>
        <label for="eager-to-learn">eager to learn</label>   <br/><br/>
        <div class="range-container">
           <input id="eager-to-learn" disabled type="range" value="0" >
         </div>
 <br><br>
         <label for="front-end">front-end</label><br><br>
          <div class="range-container">
            <input id="front-end" disabled type="range" value="0"/>
          </div>
 <br><br>
          <label for="SEO">SEO</label>
<br><br>
          <div class="range-container">
            <input id="SEO" disabled type="range" value="0"/>
         </div>
    </form>
  </div>
</body>
</html>

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