Как получить высоту элемента после его прокрутки? - PullRequest
1 голос
/ 22 апреля 2020

В приведенном ниже фрагменте кода при нажатии на текст This is four в заголовке он будет прокручиваться до 4-го раздела. До прокрутки вниз заголовка есть некоторая высота x, а после прокрутки заголовок становится липким и увеличивается в высоту.

Как я могу получить высоту заголовка после того, как он стал липким? Причина, по которой я хочу это сделать, заключается в том, что прокрутка не go точно в верхней части каждого раздела. Секция продолжает обрезаться. Я думаю, это связано с тем, что высота липкого заголовка постоянно меняется. Поэтому я хочу прокрутить в окне высоту липкого заголовка, чтобы секции правильно выстроились.

body {
  margin: 0;
  font-size: 28px;
}

#navbar {
  overflow: hidden;
  background-color: #333;
  padding: 25px 16px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  text-decoration: none;
  font-size: 17px;
  margin-right: 15px;
}

.content {
  padding: 16px;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 100;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
}

.common {
  border: 1px solid black;
  padding: 200px 10px;
  margin-bottom: 20px;
}
<body>
  <div class="header">
    <p>Scroll down to see the sticky effect.</p>
  </div>

  <div id="navbar">
    <a onclick="headerClick(this); return false;" href="#">This is One</a>
    <a onclick="headerClick(this); return false;" href="#">This is Two</a>
    <a onclick="headerClick(this); return false;" href="#">This is Three</a>
    <a onclick="headerClick(this); return false;" href="#">This is Four</a>
  </div>

  <div class="content">
    <div class="common" id="One">This is the first</div>
    <div class="common" id="Two">Two</div>
    <div class="common" id="Three">Three</div>
    <div class="common" id="Four">Four</div>
    <div class="common" id="Five">Five</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
  </div>

  <script>
    window.onscroll = function() {
      myFunction()
    };

    var navbar = document.getElementById("navbar");
    var sticky = navbar.offsetTop;

    function myFunction() {
      if (window.pageYOffset >= sticky) {
        navbar.classList.add("sticky")
        document.getElementById("navbar").style.padding = "40px 16px";
      } else {
        navbar.classList.remove("sticky");
        document.getElementById("navbar").style.padding = "25px 16px";
      }
    }

    function headerClick(elem) {
      if (elem.innerHTML === 'This is One') {
        document.getElementById("One").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Two') {
        document.getElementById("Two").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Three') {
        document.getElementById("Three").scrollIntoView();
      }
      if (elem.innerHTML === 'This is Four') {
        document.getElementById("Four").scrollIntoView();
      }
    }
  </script>

</body>

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Проблема

Используемая вами функция scrollIntoView работает так, как задумано. Однако, поскольку вы прокручиваете только до top элемента, верхняя часть скрыта липкой панелью навигации position: fixed. Что мы можем сделать, чтобы решить это? Отрегулируйте положение прокрутки после использования scrollIntoView.


Обходной путь

Вы спросили, как получить высоту элемента после прокрутки мимо него. Вы хотели получить высоту элемента, чтобы можно было регулировать положение прокрутки после использования scrollIntoView. Однако это не обязательно. Просто добавьте класс (или встроенный стиль), который увеличивает высоту navbar, затем измерьте его высоту, а затем отмените сделанные вами изменения (я сделал это на var stickyHeight = ...).

После у вас есть высота липкого элемента, вы можете перенастроить положение прокрутки после использования scrollIntoView (вычитая липкую высоту навигационной панели из позиции после того, как scrollIntoView произойдет). Однако все еще есть проблемы: когда вы нажимаете на заголовок, когда навигационная панель еще не зафиксирована, и первый элемент.

Почему щелкает заголовок, когда навигационная панель не исправлена ​​проблема? Это связано с тем, что перед настройкой панели навигации на position: fixed он все еще находится в нормальном потоке документа, а его высота изменяет высоту документа. Когда он зафиксирован, он выходит из обычного потока документов, а его высота удаляется из высоты документа. Это означает, что мы должны перенастроить формулу вычитания, когда это произойдет. Я сделал это в следующем решении.

Почему проблема с первым элементом? Ну, это в основном из-за дизайна, который вы хотите. Вы просто не можете показать самую верхнюю часть элемента, пока полоска заклеена. Попробуйте очень медленно прокрутить вручную, чтобы понять, что я имею в виду.


Решение

Вот рабочее решение. Попробуйте запустить его.

window.onscroll = function() {
  myFunction()
};

var navbar = document.getElementById("navbar");
var sticky = navbar.offsetTop;
// Getting sticky and nonStickyHeight for scroll readjustments
var nonStickyHeight = navbar.scrollHeight
var stickyHeight = (() => {
  navbar.style.padding = "40px 16px" // Or add the class that adds padding
  let result = navbar.scrollHeight
  navbar.style.padding = '' // Or remove the class that adds padding
  return result
})()

function myFunction() {
  if (window.pageYOffset >= sticky) {
    navbar.classList.add("sticky")
    document.getElementById("navbar").style.padding = "40px 16px";
  } else {
    navbar.classList.remove("sticky");
    document.getElementById("navbar").style.padding = "25px 16px";
  }
}

function headerClick(elem) {
  let firstElementClicked = false
  let navbarIsSticky = false
  
  // Check if navbar is stickied when the headings are clicked
  if (navbar.scrollHeight === stickyHeight) navbarIsSticky = true
  
  if (elem.innerHTML === 'This is One') {
    document.getElementById("One").scrollIntoView();
    firstElementClicked = true
  }
  if (elem.innerHTML === 'This is Two') {
    document.getElementById("Two").scrollIntoView();
  }
  if (elem.innerHTML === 'This is Three') {
    document.getElementById("Three").scrollIntoView();
  }
  if (elem.innerHTML === 'This is Four') {
    document.getElementById("Four").scrollIntoView();
  }
  
  // If the navbar is stickied and it's not the first element, just subtract the stickyHeight from the scroll position
  if (!firstElementClicked && navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - stickyHeight - 5)
  
  else if (firstElementClicked && !navbarIsSticky)
    window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight)
  
  // If the navbar is not stickied, you have to take account the nonStickyHeight that will be removed from the document's height when the navbar is stickied
  else if (!navbarIsSticky) window.scroll(window.pageXOffset, window.pageYOffset - nonStickyHeight - stickyHeight - 5)
}
* {
  /*scroll-behavior: smooth;*/
}

body {
  margin: 0;
  font-size: 28px;
}

#navbar {
  overflow: hidden;
  background-color: #333;
  padding: 25px 16px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  text-decoration: none;
  font-size: 17px;
  margin-right: 15px;
}

.content {
  padding: 16px;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 100;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
}

.common {
  border: 1px solid black;
  padding: 200px 10px;
  margin-bottom: 20px;
}
<body>
  <div class="header">
    <p>Scroll down to see the sticky effect.</p>
  </div>

  <div id="navbar">
    <a onclick="headerClick(this); return false;" href="#">This is One</a>
    <a onclick="headerClick(this); return false;" href="#">This is Two</a>
    <a onclick="headerClick(this); return false;" href="#">This is Three</a>
    <a onclick="headerClick(this); return false;" href="#">This is Four</a>
  </div>

  <div class="content">
    <div class="common" id="One">This is the first</div>
    <div class="common" id="Two">Two</div>
    <div class="common" id="Three">Three</div>
    <div class="common" id="Four">Four</div>
    <div class="common" id="Five">Five</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
    <div class="common">Filler div to make scrolling longer</div>
  </div>
</body>
1 голос
/ 22 апреля 2020

Контент обрезается, потому что он заканчивается за панелью навигации, так что вы можете, например, добавить дополнительный отступ в верхнюю часть .content, чтобы, когда он попадает за панель навигации, он просто расширялся.

Почувствуйте Вы можете свободно изменять значения, так как они могут быть немного нервными, но, кажется, имеют эффект, который вы ищете.

window.onscroll = function() {
  myFunction();
};

var navbar = document.getElementById("navbar");
var sticky = navbar.offsetTop;

function myFunction() {
  if (window.pageYOffset >= sticky) {
    navbar.classList.add("sticky");
    document.getElementById("navbar").style.padding = "40px 16px";
    document.querySelector(".content").style.paddingTop = "116px";
  } else {
    navbar.classList.remove("sticky");
    document.querySelector(".content").style.paddingTop = "16px";
    document.getElementById("navbar").style.padding = "25px 16px";
  }
}

function headerClick(elem) {
  if (elem.innerHTML === "This is One") {
    document.getElementById("One").scrollIntoView();
  }
  if (elem.innerHTML === "This is Two") {
    document.getElementById("Two").scrollIntoView();
  }
  if (elem.innerHTML === "This is Three") {
    document.getElementById("Three").scrollIntoView();
  }
  if (elem.innerHTML === "This is Four") {
    document.getElementById("Four").scrollIntoView();
  }
}
body {
  margin: 0;
  font-size: 28px;
}

#navbar {
  overflow: hidden;
  background-color: #333;
  padding: 25px 16px;
}

#navbar a {
  float: left;
  display: block;
  color: #f2f2f2;
  text-align: center;
  text-decoration: none;
  font-size: 17px;
  margin-right: 15px;
}

.content {
  padding: 16px;
}

.sticky {
  position: fixed;
  top: 0;
  width: 100%;
  z-index: 100;
  box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.16);
}

.common {
  border: 1px solid black;
  padding: 200px 10px;
  margin-bottom: 20px;
}
<div class="header">
  <p>Scroll down to see the sticky effect.</p>
</div>

<div id="navbar">
  <a onclick="headerClick(this); return false;" href="#">This is One</a>
  <a onclick="headerClick(this); return false;" href="#">This is Two</a>
  <a onclick="headerClick(this); return false;" href="#">This is Three</a>
  <a onclick="headerClick(this); return false;" href="#">This is Four</a>
</div>

<div class="content">
  <div class="common" id="One">This is the first</div>
  <div class="common" id="Two">Two</div>
  <div class="common" id="Three">Three</div>
  <div class="common" id="Four">Four</div>
  <div class="common" id="Five">Five</div>
  <div class="common">Filler div to make scrolling longer</div>
  <div class="common">Filler div to make scrolling longer</div>
  <div class="common">Filler div to make scrolling longer</div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...