javascript - 为什么在计算scrollPercent时需要从windowHeight减少clientHeight?

标签 javascript scroll window

我试图用进度条显示用户在页面 a 上滚动了多少,我已经做到了。但我在这里有点困惑。

这是我发现的计算 scrollPercent 的代码,效果很好


windowHeight = Math.max(
html.clientHeight,
html.scrollHeight,
html.offsetHeight,
body.scrollHeight,
body.offsetHeight
);

const  scrolledPercent =
((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
100;

最初,我想,要获取 scrollPercent ,我需要获取当前的 scrollPosition 并将该数字除以页面的总高度,然后乘以 >100% 。这就像通常我们如何获取某物的 % 一样。

const  scrolledPercent = 
((html.scrollTop || body.scrollTop) / windowHeight) * 100;

但是这条线并没有像我预期的那样工作。如果我这样做,即使我滚动到页面末尾,进度条也不会达到 100%。我不明白为什么我在这里错了!

所以,我的问题是为什么我们需要从 windowHeight 减少 html.clientHeight

谢谢。

此处演示:

// --------------------------------------------
// variables
// --------------------------------------------

const html = document.documentElement,
  body = document.body,
  countryList = document.querySelector(".country__list");
scrollNavigated = document.querySelector(".scroll__navigated");
let windowHeight;

// --------------------------------------------
// function
// --------------------------------------------

async function prepareListOfCountries() {
  let list = await fetch("https://restcountries.eu/rest/v2/all");
  list = Array.from(await list.json());
  let markup = list
    .map((country, index) => {
      return `<li class="country__item card">
              <span class="country__name">${country.name}</span
              ><span class="country__capital">${country.capital}</span>
              <a href="javascript:;" class="country__flag">
               <img src= '${country.flag}'> </a>
             
        </li>`;
    })
    .slice(0, 30)
    .join(" ");
  countryList.innerHTML = markup;
}

function updateScrolledStatus(e) {
  windowHeight = Math.max(
    html.clientHeight,
    html.scrollHeight,
    html.offsetHeight,
    body.scrollHeight,
    body.offsetHeight
  );

  const scrolledPercent =
    ((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
    100;
  // const scrolledPercent =
  //   ((html.scrollTop || body.scrollTop) / windowHeight) * 100; // this line doesnot work
  scrollNavigated.style.width = scrolledPercent + "%";
}

prepareListOfCountries();

// --------------------------------------------
// event-handler
// --------------------------------------------

window.addEventListener("scroll", updateScrolledStatus);
*::after,
*::before,
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
 Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}

.container {
  max-width: 980px;
  margin: 0 auto;
}

.justify-between {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.items-center {
  display: flex;
  align-items: center;
}

.card {
  background-color: #fff;
  box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.054);
  border-radius: 4px;
  padding: 16px;
}

.country__flag img {
  height: 100%;
  width: 100%;
}

.header {
  padding: 24px 0;
  background-color: #333;
  color: #f1f1f1;
  position: -webkit-sticky;
  position: sticky;
}

.content {
  padding: 50px 0;
}

.content__form {
  margin: 0 auto;
  margin-bottom: 32px;
}

.content__search {
  width: 50%;
  padding: 12px 16px;
  border-radius: 20px;
  border: 1px solid #ddd;
  transition: 0.2s;
}

.content__search:hover {
  box-shadow: 0 1px 6px 0 rgba(32, 33, 36, 0.28);
}

.content__search:focus {
  outline: none;
}

.country__list {
  margin-top: 50px;
  margin: 10px auto;
}

.country__item {
  display: flex;
  justify-content: space-between;
  margin-bottom: 16px;
}

.country__name, .country__capital, .country__flag {
  width: 33.33%;
}

.country__flag {
  width: 32px;
  height: 24px;
}

.scroll__navigator {
  height: 2px;
  margin: 0 auto 32px;
  background-color: #333;
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}

.scroll__navigated {
  display: block;
  height: 100%;
  width: 0;
  background: orangered;
  transition: 0.3s linear;
}
<body>
    <header class="header">
      <div class="container">
        All countries list
      </div>
    </header>
    <main class="content">
      <div class="container">
        <form class="content__form">
          <input class="content__search" />
        </form>
        <div class="scroll__navigator">
          <span class="scroll__navigated"></span>
        </div>
        <section class="country">
          <ul class="country__list">
            <li class="country__item card">
              <span class="country__name">Nepal</span
              ><span class="country__capital">Kathmandu</span>
              <a href="javascript:;" class="country__flag"></a>
            </li>
          </ul>
        </section>
      </div>
    </main>
     
  </body>
 

最佳答案

举个例子,假设您的客户端高度为 100px,整个页面的高度为 500px

当滚动位置为 0px 时,您可以看到网站的前 100px,因此从 0px >100px

在滚动位置 100px 处,您可以看到范围 100px200px,因为您已经移动了页面,因此可见范围,以 100px 为单位。

在滚动位置 400px 处,您可以看到 400px500px 的范围 - 换句话说,您已滚动到底部.

这表明页面的可滚动高度 (400px) 小于页面的实际高度 (500px),即客户端的高度。

要获得滚动的百分比,需要使用可滚动的高度,因此需要用页面的高度减去客户端的高度才能得到正确的值,否则永远无法滚动到底端。在只有 500px 长的网站上不可能滚动 500px!

关于javascript - 为什么在计算scrollPercent时需要从windowHeight减少clientHeight?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61478766/

相关文章:

java - SwingBuilder : scrollPane

python - 如何在使用 Selenium 无限滚动的网页中多次滚动

php - 将参数传递给新窗口php

windows - 当窗口移动到另一个显示器时是否有通知?

javascript - 删除IE中的窗口属性

javascript - 无法使用维度对象外部的数据呈现系列图表

javascript - Angular 组件 Hook - 也适用于指令?

php - 如何处理 MVC 网站中查看特定的 Javascript

javascript - 类切换 [jQuery/CSS]

css - DIV/部分的自定义滚动