(已解决)导航栏滚动到视图中导致单击时链接失败

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

编辑:问题已解决。我将保留此帖子,以帮助可能面临相同问题的其他人。该错误与让浏览器处理导航栏上的点击有关。通过添加带有 preventDefault() 的 onclick 函数来覆盖点击事件默认反应,然后使用 JS 命令将内容滚动到正确的部分来解决。最后有codePen的链接。


我正在开发在线餐厅菜单。它有一个固定在顶部的水平导航栏。导航栏上的链接水平滚动,内容垂直滚动。这些链接指向同一页面上的#sections。我设法使链接在相应的内容部分滚动时突出显示。当用户滚动主要内容时,我还设法让菜单项自己滚动到屏幕中央。但这就是问题所在。当用户单击菜单链接时,最后一个功能会导致滚动失败。好像这个函数打断了点击触发的滚动,所以页面只滚动了10px就停止了。如果我删除菜单项的自动居中功能,单击将再次起作用。我试图通过将 onclick 函数附加到菜单链接来强制页面滚动,但它仍然不起作用。以下是解释的当前代码:

// Get all sections that have an ID defined
const sections = document.querySelectorAll("section[id]");

// Add an event listener listening for scroll
window.addEventListener("scroll", navHighlighter);

function navHighlighter() {

  // Get current scroll position
  let scrollY = window.pageYOffset;

  // Now we loop through sections to get height, top and ID values for each
  sections.forEach(current => {
    const sectionHeight = current.offsetHeight;
    const sectionTop = (current.getBoundingClientRect().top + window.pageYOffset) - 70;
    sectionId = current.getAttribute("id");

    /*
    - If our current scroll position enters the space where current section on screen is, add .active class to corresponding navigation link, else remove it
    - To know which link needs an active class, we use sectionId variable we are getting while looping through sections as an selector
    */
    if (scrollY > sectionTop && scrollY <= sectionTop + sectionHeight) {
      theone = document.querySelector('a.menu_item[href="#' + sectionId + '"]');
      theone.classList.add('active');
    } else {
      document.querySelector('a.menu_item[href="#' + sectionId + '"]').classList.remove('active');
    }
  });
  navScroll(theone); //this is the line that breaks the scroll started by clicks. EDIT: started working with preventDefault.
}

//brings the menu link to the visible area when user scroll thru content. Can also be replaced with scrollIntoView.
function navScroll(item) {
  const menu = document.getElementById("menu");
  const menu_w = menu.offsetWidth;
  const item_w = item.offsetWidth;
  const item_x = item.offsetLeft;
  menu.scrollLeft = item_x - (menu_w / 2) + (item_w / 2);
}

//EDIT: it is now working since I added preventDefault.
function forceScroll(sectionID) {
  event.preventDefault();
  const section = document.getElementById(sectionID);
  window.scrollTo(0, section.offsetTop);
}
.content {
  height: 500px;
  border-bottom: 1px solid black;
}

.scroll {
  white-space: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  -ms-overflow-style: -ms-autohiding-scrollbar;
  scroll-behavior: smooth;
}

.scroll::-webkit-scrollbar {
  display: none;
}

div#menu {
  position: fixed;
  top: 0px;
  width: 100%;
  height: 50px;
  z-index: 999;
  text-align: center;
}

a.menu_item {
  display: inline-block;
  vertical-align: middle;
  text-align: center;
  height: 50px;
  background-color: #fff;
  color: #000;
}

a.menu_item.active {
  background-color: #000;
  color: #fff;
}

section {
  display: block;
}
<div id="menu" class="scroll">
  <a class="menu_item" href="#sec_1" onclick="forceScroll('sec_1')">Link 1</a>
  <a class="menu_item" href="#sec_2" onclick="forceScroll('sec_2')">Link 2</a>
  <a class="menu_item" href="#sec_3" onclick="forceScroll('sec_3')">Link 3</a>
</div>
<section id="sec_1">
  <div class="content">Some content</div>
</section>
<section id="sec_2">
  <div class="content">Some content</div>
</section>
<section id="sec_3">
  <div class="content">Some content</div>
</section>

所以基本上,如果我不使用 navScroll() 函数,一切正常。 .active 类将在内容滚动时相应地应用于菜单项,无论是用户滚动还是通过单击菜单中的链接,这都会使内容滚动到相应的部分。 但是当我添加 navScroll 函数,使菜单项滚动到视图中时,只有当用户直接滚动内容时,事情才会起作用。单击链接时,滚动很快被打断,什么也没有发生。

如果您只保留 Javascript,我将不胜感激,但如果它成为解决此问题的唯一方法,我会接受 jQuery。

更新 1:问题似乎只发生在 Chrome(版本 112.0.5615.49)中。我在 Mac 上,还没有在 PC 上测试过。 Safari 还存在一些小错误,例如滚动不流畅和不应用顶部偏移,因此部分标题不会出现在导航栏后面。但这些都不是这里的主要问题。

更新 2:我能够在 codePen 中重现错误。该问题与平滑滚动行为有关。没有它,卷轴工作正常。有了它,滚动只有在我删除 navScroll() 调用时才有效,这会使导航栏链接滚动到视图中。好像当第二个平滑滚动开始时,当前的滚动被打断了。

这是代码笔链接:https://codepen.io/pen/GRYgxda

更新 3:我设法通过向链接添加 onclick='forceScroll([section_id])' 使一切正常。 event.preventDefault() 行将在点击链接时停止浏览器默认操作,然后通过 JS 命令 window.scrollTo() 使窗口滚动到正确的部分。

javascript scroll navbar event-listener js-scrollintoview
© www.soinside.com 2019 - 2024. All rights reserved.