当鼠标位于固定元素并且我需要指针事件时如何滚动页面?如何从页面上的任何位置滚动一个特定元素?

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

我需要滚动页面上的一个特定元素,即使鼠标没有悬停在该元素上...

我通常会将需要滚动的 div 放在具有透明背景的顶层,但我有一个需要在同一页面上查看/交互的导航菜单。

根据我的经验,CSS 非常挑剔;一项原本应该是美观的改变最终只会改变元素之间的相互作用,这是令人沮丧的。我已经投入这个项目几个小时了,我真的不想为了像这样的一个错误而从头开始......并且必须在每次添加 CSS 后测试网站是否工作。

我将放一个 jsfiddle 来说明我的网站的结构。

html {
  overflow: hidden;
}

.fixed {
  position: fixed;
  background-color: blue;
  width: 50%;
}

.scrollable {
  background-color: red;
  height: 100vh;
  padding-left: 50%;
  overflow-y: scroll;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <div class="fixed">
    <h1>
    Lorem ipsum dolor sit amet
    </h1>
    
  </div>
  <div class="scrollable">
    <ul>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
     </ul>
   </div>
</body>
</html>

我可以在红色 div 上的任何位置滚动并且它可以工作,但是如果我在蓝色 div 上滚动,红色 div 将不会滚动。将蓝色 div 更改为

pointer-events: none;
使一切正常(这是我在网上找到的唯一答案),除了我在蓝色 div 内有一个带有指针事件的导航栏。您可能会认为 HTML 存在了几个世纪后会找到一种简单的方法来让固定元素具有指针事件和滚动事件!

TL;DR 有没有一种方法可以使屏幕上任意位置的滚动滚动一个特定的 div? 预先感谢。

迄今为止最好的解决方案:

const s = document.querySelector(".bottom-half");
    const f = document.querySelector(".top-container");
    var isRunning = false;
    f.addEventListener('wheel', function(e) {
        if (!isRunning) {
            isRunning = true;
            s.scrollTop += (e.deltaY < 1) ? -300 : 300;
        }
        isRunning = false;
    });
javascript html css
2个回答
1
投票

您可以使用

wheel
事件来捕获不可滚动元素上的“滚动”,然后将其转换为固定的
scrollTop

const s = document.querySelector(".scrollable");
const f = document.querySelector(".fixed");

f.addEventListener('wheel', (e) => (s.scrollTop += (e.deltaY < 1) ? 30 : -30));
html {
  overflow: hidden;
}

.fixed {
  position: fixed;
  background-color: blue;
  width: 50%;
}

.scrollable {
  background-color: red;
  height: 50vh;
  padding-left: 50%;
  overflow-y: scroll;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <div class="fixed">
    <h1>
    Lorem ipsum dolor sit amet
    </h1>
    
  </div>
  <div class="scrollable">
    <ul>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
       <li>_________</li>
     </ul>
   </div>
</body>
</html>


0
投票

基于 0stone0 的答案构建(添加了一些内容以使滚动更平滑并测试所有指针事件)。

// scroll bar functionality for fixed element
// https://stackoverflow.com/questions/41592349/allow-pointer-click-events-to-pass-through-element-whilst-maintaining-scroll-f#
function scroller(event) {
  scrollable = document.getElementById("scrollable");
  switch (event.deltaMode) {
    case 0: //DOM_DELTA_PIXEL       Chrome
      scrollable.scrollTop += event.deltaY
      scrollable.scrollLeft += event.deltaX
      break;
    case 1: //DOM_DELTA_LINE        Firefox
      scrollable.scrollTop += 15 * event.deltaY
      scrollable.scrollLeft += 15 * event.deltaX
      break;
    case 2: //DOM_DELTA_PAGE
      scrollable.scrollTop += 0.03 * event.deltaY
      scrollable.scrollLeft += 0.03 * event.deltaX
      break;
  }
  event.stopPropagation();
  event.preventDefault()
}

document.onwheel = scroller;


// scroll to an item that inside a div
//   https://stackoverflow.com/questions/45408920/plain-javascript-scrollintoview-inside-div
function scrollParentToChild(parent, child, threshold = 0) {
  // Where is the parent on page
  const parentRect = parent.getBoundingClientRect();
  // What can you see?
  const parentViewableArea = {
    height: parent.clientHeight,
    width: parent.clientWidth,
  };
  // Where is the child
  const childRect = child.getBoundingClientRect();
  // Is the child viewable?
  const isViewableVertically = childRect.top >= parentRect.top &&
    childRect.bottom <= parentRect.top + parentViewableArea.height;
  const isViewableHorizontally = childRect.left >= parentRect.left &&
    childRect.right <= parentRect.left + parentViewableArea.width;
  // if you can't see the child try to scroll parent
  if (!isViewableVertically || !isViewableHorizontally) {
    // Should we scroll using top or bottom? Find the smaller ABS adjustment
    const scrollTop = childRect.top - parentRect.top;
    const scrollBot = childRect.bottom - parentRect.bottom;
    const scrollLeft = childRect.left - parentRect.left;
    const scrollRight = childRect.right - parentRect.right;
    if (Math.abs(scrollTop) < Math.abs(scrollBot) && Math.abs(scrollLeft) < Math.abs(scrollRight)) {
      // we're nearer to the top and left of the list
      parent.scrollTo({
        top: parent.scrollTop + scrollTop - threshold,
        left: parent.scrollLeft + scrollLeft - threshold,
        behavior: 'smooth',
      });
    } else {
      // we're nearer to the bottom and right of the list
      parent.scrollTo({
        top: parent.scrollTop + scrollBot + threshold,
        left: parent.scrollLeft + scrollRight + threshold,
        behavior: 'smooth',
      });
    }
  }
}
html,
body {
  overflow: hidden;
  margin: 0;
  padding: 0;
  background-color: pink;
}

.container {
  position: relative;
  width: 100%;
  height: 100vh;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

#stage-layer {
  position: absolute;
  width: 100vw;
  height: 100vh;
  background-color: yellow;
  margin: 0;
  padding: 0;
}

#application-layer {
  position: relative;
  height: 100%;
  margin: 0;
  padding: 0;
}

rect:hover {
  fill: blue;
}

#scrollable {
  position: relative;
  overflow: auto;
  color: hotpink;
  height: 100%;
  width: 100%;
  background-color: blue;
  padding-left: 0;
}

p:hover {
  color: white;
  transform: translateX(20px);
  transition: 0.3s;
}

.menu {
  position: fixed;
  background-color: red;
  width: 100px;
  z-index: 100;
}

.hover:hover {
  background-color: orange;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="styles.css">
  <title>Blank HTML</title>
</head>

<body>
  <div class="container">
    <svg id="stage-layer">
            <rect></rect>
        </svg>
    <div id="application-layer">
      <div class="menu">
        <p onClick="scrollParentToChild(document.getElementById('scrollable'), document.getElementById('first'));">
          go to top of page</p>
        <p onClick="scrollParentToChild(document.getElementById('scrollable'), document.getElementById('last'));">
          go to bottom of page</p>
      </div>

      <div id="scrollable">
        <li id="first">_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li class="hover">HOVER TEST</li>
        <li>_________</li>
        <li>_________</li>
        <li><a class="link" href="https://www.google.com/">LINK TEST</a></li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li>_________</li>
        <li id="last">_________</li>
      </div>

    </div>
  </div>
  <script src="/website/test/scripts.js"></script>
</body>

</html>

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