防止窗口垂直滚动,直到 div 的水平滚动条滚动到底部

13
我有一个页面垂直滚动,我希望有一个div元素可以在鼠标向下滚动时水平滚动,然后一旦水平滚动完成,就恢复垂直滚动。这是我想要实现的内容:
- 页面正常垂直滚动 - 当我到达#scroll div时,我希望页面滚动停止,并且我希望#scroll内部的内容可以垂直滚动 - 一旦我滚动到#scroll的末尾,我希望正常的页面垂直滚动重新开始。
我尝试了一些解决方案,但遇到以下问题:
- 当我水平滚动#scroll内容时,垂直页面滚动不会停止。 - 当我停止垂直滚动并到达水平滚动的末尾时,我必须滚动大约50次才能离开那个div。
以下是我目前的代码:
var scroller = {};
scroller.e = document.getElementById("scroll");

if (scroller.e.addEventListener) {
    scroller.e.addEventListener("mousewheel", MouseWheelHandler, false);
    scroller.e.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
} else scroller.e.attachEvent("onmousewheel", MouseWheelHandler);

function MouseWheelHandler(e) {

    // cross-browser wheel delta
    var e = window.event || e;
    var delta = - 30 * (Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))));

    var pst = $('#scroll').scrollLeft() + delta;

    if (pst < 0) {
        pst = 0;
    } else if (pst > $('.box-wrap').width()) {
        pst = $('.box-wrap').width();
    }

    $('#scroll').scrollLeft(pst);

    return false;
}


var toolbox = $('#scroll'),
    height = toolbox.height(),
    scrollHeight = toolbox.get(0).scrollHeight;

toolbox.off("mousewheel").on("mousewheel", function (event) {
  var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
  return !blockScrolling;
});
#wrap {
  max-width: 600px;
  margin: 0 auto;
}

#scroll {
    width: 600px;
    border: 1px solid #111;
    padding: 0px;
    margin: 0px;
    overflow-x: scroll;
    overflow-y: hidden;
}

.box-wrap{
    padding: 0px;
    margin: 0px;
    height: 200px;
    width: 2040px;
}

.box {
    height: 200px;
    width: 200px;
    padding: 0px;
    background: #123;
    display: inline-block;
    color: #fff;
    font-size: 20px;
    text-align: center;
    line-height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrap">

  <h1>asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>

  <div id="scroll">
    <div class="box-wrap">
      <div class="box">1</div>
      <div class="box">2</div>
      <div class="box">3</div>
      <div class="box">4</div>
      <div class="box">5</div>
      <div class="box">6</div>
      <div class="box">7</div>
      <div class="box">8</div>
      <div class="box">9</div>
      <div class="box">10</div>     
    </div>
  </div>

  <h1>asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>

</div>

这种解决方案的问题在于,当我到达水平滚动部分时,垂直页面滚动不会停止。

有人有什么建议可以实现我想要的吗? 如果我没有解释清楚,请告诉我。

谢谢!


这可能是您尝试实现的一部分:https://dev59.com/Z3A65IYBdhLWcg3wvhXi - moronator
5个回答

10

你差点就到了。这是一个阻止你滚动的屏障:

$("#scroll").off("mousewheel").on("mousewheel", function(ev) {
  var el = $(ev.currentTarget);
  return ev.originalEvent.deltaY > 0
    ? el[0].scrollWidth - el.scrollLeft() <= el.innerWidth()
    : el.scrollLeft() === 0;
});

更新的笔记
要观看它们,请在鼠标滚轮事件中使用此日志记录器:

console.log(
  'ev.originalEvent.deltaY:', ev.originalEvent.deltaY,
  '\nel[0].scrollWidth:',el[0].scrollWidth, 
  '\nel.scrollLeft():', el.scrollLeft(), 
  '\nel.innerWidth()',el.innerWidth()
);

谢谢您的建议,但我已尝试过了。当在#scroll div内滚动时,垂直页面滚动并没有停止。 - Axion
只要在#scroll内滚动(因为那是你绑定mousewheel的地方),它就能正常工作。如果你想始终在元素进入视图时滚动该元素,则需要在窗口滚动时绑定,当元素滚动到视图中时返回false,滚动元素直到结束,然后再开始返回true。但是,即使用户在元素外部滚动,他们也无法摆脱滚动锁定,这是一个巨大的UX问题。你会让很多用户因为沮丧而关闭你的网站并永远不再回来。 - tao
这在Chrome中运行得很好!有什么办法让它在Firefox中工作吗? - Axion

7

使用e.preventDefault()可以避免屏幕在垂直方向上滚动。然而,它只需要应用于水平容器允许更多滚动的情况下,根据滚动方向向左或向右

这显然仅在在水平可滚动元素上执行滚动时才起作用。

实现示例(向下滚动以进行测试):

let scrollSpeed = 30;
let scroller = document.getElementById("scroll");

scroller.addEventListener("mousewheel", e=>{
  // block if e.deltaY==0
  if( !e.deltaY ) return;
  // Set scrollDirection (-1 = up // 1 = down)
  let scrollDirection = (e.deltaY > 0) ? 1 : -1;
  // convert vertical scroll into horizontal
  scroller.scrollLeft += scrollSpeed * scrollDirection;
  let scrollLeft = Math.round(scroller.scrollLeft);
  // calculate box total vertical scroll 
  let maxScrollLeft = Math.round( scroller.scrollWidth - scroller.clientWidth );
  // if element scroll has not finished scrolling
  // prevent window to scroll
  if( 
    (scrollDirection === -1  && scrollLeft > 0) ||
    (scrollDirection === 1 && scrollLeft < maxScrollLeft ) 
  ) e.preventDefault()
  // done!
  return true;
}, false);
#wrap {
  max-width: 600px;
  margin : auto;
}

.dummy-content{
  height: 400px;
  background: red
}

#scroll {
    overflow-x: scroll;
    overflow-y: hidden;
    margin :20px 0;
}

#scroll>div:first-child{
    height: 200px;
    width: 2040px;
    background-image: linear-gradient(to right ,red, yellow);
}
<div id="wrap">
<div class='dummy-content'></div>
  <div id="scroll">
      <div>
          <!-- Your horizontal content -->
      </div>
  </div>
  <div class='dummy-content'></div>
</div>


嗯,我尝试过了,但是当我往下滚动鼠标滚轮时,水平部分仍然会移动。 - Axion
我更新了代码,请再试一次(在我的Chrome浏览器中可以工作) - colxi
谢谢!我在Chrome中测试过了,效果很棒...但是我无法让它在Firefox中工作。你有任何想法为什么它不能在FF中工作吗? - Axion
@Axion 使用'wheel'事件替代'mousewheel'。请注意,所有示例都会向实现此功能的任何应用程序添加真正的错误。例如,Chrome将开始垂直滚动body元素和具有wheel事件的元素。Firefox也存在类似的问题,但有时无法附加到元素滚动上。只有一个“always preventDefault()”解决方案可以防止奇怪的滚动行为,但这将无法回答问题。更好的解决方案可能是一条新的CSS滚动规则,但这需要标准机构和浏览器供应商参与。 - CubicleSoft

5

https://codepen.io/anon/pen/oOgrEY

正如安德烈·格奥尔基乌 所解释的那样。它只是缺少:

e.preventDefault(); // << add this
e.stopPropagation(); // << add this

之前 return false;

var scroller = {};
scroller.e = document.getElementById("scroll");

if (scroller.e.addEventListener) {
  scroller.e.addEventListener("mousewheel", MouseWheelHandler, false);
  scroller.e.addEventListener("DOMMouseScroll", MouseWheelHandler, false);
} else scroller.e.attachEvent("onmousewheel", MouseWheelHandler);

function MouseWheelHandler(e) {
  // cross-browser wheel delta
  var e = window.event || e;
  var delta = -30 * Math.max(-1, Math.min(1, e.wheelDelta || -e.detail));

  var pst = $("#scroll").scrollLeft() + delta;

  if (pst < 0) {
    pst = 0;
  } else if (pst > $(".box-wrap").width()) {
    pst = $(".box-wrap").width();
  }

  $("#scroll").scrollLeft(pst);
  e.preventDefault(); // << add this
  e.stopPropagation(); // << add this
  return false;
}

$("#scroll").off("mousewheel").on("mousewheel", function(ev) {
  var el = $(ev.currentTarget);
  return ev.originalEvent.deltaY > 0
    ? el[0].scrollWidth - el.scrollLeft() <= el.innerWidth()
    : el.scrollLeft() === 0;
});
#wrap {
  max-width: 600px;
  margin: 0 auto;
}

#scroll {
    width: 600px;
    border: 1px solid #111;
    padding: 0px;
    margin: 0px;
    overflow-x: scroll;
    overflow-y: hidden;
}

.box-wrap{
    padding: 0px;
    margin: 0px;
    height: 200px;
    width: 2040px;
}

.box {
    height: 200px;
    width: 200px;
    padding: 0px;
    background: #123;
    display: inline-block;
    color: #fff;
    font-size: 20px;
    text-align: center;
    line-height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrap">

  <h1>asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>

  <div id="scroll">
    <div class="box-wrap">
      <div class="box">1</div>
      <div class="box">2</div>
      <div class="box">3</div>
      <div class="box">4</div>
      <div class="box">5</div>
      <div class="box">6</div>
      <div class="box">7</div>
      <div class="box">8</div>
      <div class="box">9</div>
      <div class="box">10</div>     
    </div>
  </div>

  <h1>asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>
  
</div>

测试版本:Version 73.0.3683.86 (官方构建) (64位),Firefox 66.0.2 (64位),Microsoft Edge 42.17134.1.0(Microsoft EdgeHTML 17.17134),Internet Explorer 11.648.17134.0


1
为了让 #scroll div 粘在页面上,不要停止正常的垂直滚动。相反,增加 div 的顶部位置,使其看起来像是 #scroll div 停留在同一位置。
我将需要粘贴的部分包裹在 #fixedSec 中。
此外,要让 .box-wrap div 随着垂直窗口滚动而滚动,请使用 scrollTop() 函数,然后相应地转换您的 .box-wrap
代码演示链接是 this
以下是代码。

var scroller = {};
var topSpace = $('#topHeading').height();
const scrollWidth = $('.box-wrap').width();
console.log($(window).width());

scroller.e = document.getElementById("scroll");
$(window).scroll(function(event) {
  var scroll = $(window).scrollTop();

  if (scroll > 785 && ((765 - scroll) > ($(window).width() - $(".box-wrap").width()))) {


    var scrollPos = scroll - 770;
    $('#fixedSec').css({
      'top': scrollPos + "px"
    })
    $('.box-wrap').css('transform', 'translateX(' + (755 - scroll) + 'px)');



  }


});
h1 {
  width: 500px;
}

#wrap {
  margin: 0 auto;
}

#fixedSec {
  position: relative;
}

#scroll {
  width: 100vw;
  border: 1px solid #111;
  padding: 0px;
  margin: 0px;
  overflow-x: scroll;
  overflow-y: hidden;
}

.box-wrap {
  padding: 0px;
  margin: 0px;
  height: 200px;
  width: 2040px;
}

.box {
  height: 200px;
  width: 200px;
  padding: 0px;
  background: #123;
  display: inline-block;
  color: #fff;
  font-size: 20px;
  text-align: center;
  line-height: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrap">

  <h1 id="topHeading">asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas
    fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh
    sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas
    kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>

  <div id="fixedSec">
    <div id="scroll">
      <div class="box-wrap">
        <div class="box">1</div>
        <div class="box">2</div>
        <div class="box">3</div>
        <div class="box">4</div>
        <div class="box">5</div>
        <div class="box">6</div>
        <div class="box">7</div>
        <div class="box">8</div>
        <div class="box">9</div>
        <div class="box">10</div>
      </div>

    </div>

    <h1>asl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas
      fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh
      sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs
      kjfhas kljfh sakjfhas fsdkasl fjas fhljksa flkjsahf kjsah fkjlsa fkjshf kljsha fkljhs kjfhas kljfh sakjfhas fsdk</h1>
  </div>


</div>

注意

即使您将#scrolloverflow设置为隐藏,该解决方案仍然有效,因为它使用transform: translateX()函数来水平滚动.box-wrap。 个人建议将overflow:hidden设置为隐藏,因为滚动条看起来很丑。

希望这个实现对您有用。


0
您需要在 mouseWheelHandler 中使用 e.preventDefault() 停止默认事件行为(垂直滚动)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接