Mousemove /滚动到下一个哈希

时间:2018-05-11 17:44:32

标签: javascript jquery html

我添加了以下代码,以便用鼠标滚动(滚动点击+拖动,而不是通过鼠标滚轮)。到目前为止,这么好 - 像魅力一样:

var clicked = false, clickY;
$(document).on({
'mousemove': function(e) {
    clicked && updateScrollPos(e);
},
'mousedown': function(e) {
    clicked = true;
    clickY = e.pageY;
},
'mouseup': function() {
    clicked = false;
    $('html').css('cursor', 'auto');
}
});

var updateScrollPos = function(e) {
    $('html').css('cursor', 'row-resize');
    $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
}

我正在尝试更改此滚动行为,以便每个方向点击+拖动鼠标移动跳转到下一个/最接近的哈希,例如一个10px的阻力。换句话说,鼠标向上滚动应该跳转到当前位置上方的下一个哈希值,向下滚动应该跳转到下面的下一个哈希值。

这似乎没有涉及任何相关问题。

  
    

编辑:

  

我想我需要替换

$(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));

以下链接中的部分解决方案。不幸的是,这似乎高于我的技能水平:

how to get nearest anchor from the current mouse position on mouse move

  
    

解决方案:

  

我使用了Saeed Ataee的答案,对这段代码非常满意,但是用我已经使用的下一个替换了鼠标滚轮代码部分,恰好在我的工作上做得更好(我相信他很好,只是在这里提供替代方案):

$('#nav').onePageNav();


var $current, flag = false;

$('body').mousewheel(function(event, delta) {
if (flag) { return false; }
$current = $('div.current');

if (delta > 0) {
    $prev = $current.prev();

    if ($prev.length) {
        flag = true;
        $('body').scrollTo($prev, 1000, {
            onAfter : function(){
                flag = false;
            }
        });
        $current.removeClass('current');
        $prev.addClass('current');
    }
} else {
    $next = $current.next();

    if ($next.length) {
        flag = true;
        $('body').scrollTo($next, 1000, {
            onAfter : function(){
                flag = false;
            }
        });
        $current.removeClass('current');
        $next.addClass('current');
    }
}

event.preventDefault();

});

3 个答案:

答案 0 :(得分:4)

我希望这有助于你

let currentElement = 0,
  maxLength = $("div[id^='section']").length;

$(document).ready(function() {
  $(document).on("mousewheel", function(e) {
    if (e.originalEvent.wheelDelta > 0) {
      currentElement = (currentElement > 0) ? currentElement - 1 : 0;

      $("html, body").animate({
          scrollTop: $("#section-" + currentElement).offset().top
        },
        200
      );
    } else {
      currentElement = (currentElement < maxLength - 1) ? currentElement + 1 : currentElement;
      $("html, body").animate({
          scrollTop: $("#section-" + currentElement).offset().top
        },
        200
      );
    }
  });
});
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="section-0">Section 1</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-1">Section 2</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-2">Section 3</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-3">Section 4</div>
</body>

</html>

答案 1 :(得分:3)

我看到你需要解决的一些事情:

1)标记并找到要滚动到的元素

在您要滚动到的元素上添加类似ID属性或类的内容。使用ID属性,您可以使用旧式哈希URL导航(http://some-url/#some-anchor)以及新方法进行导航。

我们假设您使用格式#scroll-to-A#scroll-to-B等作为锚点的ID。然后,您可以使用document.querySelectorAll将包含字符串scroll-to的ID定位到所有元素:

const scrollElements = document.querySelectorAll("[id*='scroll-to']");

  

querySelectorAll不返回Element数组,但是a   节点列表。您可以使用将其转换为数组   Array.from(scrollElements)。了解我所呈现的其余代码可能很有用。

2)给定页面上的任何垂直滚动位置,找到下一个应该滚动到哪个元素

使用Element.getBoundingClientRect(),您可以确定元素所在屏幕顶部的像素数:

function getTopPositionForElement(el) {
    return el.getBoundingClientRect().top + window.scrollY;
}

然后,您可以通过检查哪个元素最接近页面顶部来计算要滚动到下一个元素。 使用Array.sort确定数组中最接近的数据,然后选择列表中的第一个元素:

function calculateNextElement(direction) {
    // Handle the cases for direction here...

    switch (direction) {
        case "down": 
            return scrollElements.sort((a, b) => { 
                return getTopPositionForElement(a) > getTopPositionForElement(b) ? -1 : 1;
            })[0];
        case "up":
            // Fill in here
        default: 
            // Fill in here
    }
}
  

你必须在这里添加的一件事是处理这两种情况   用户滚动的方向。这个实现只涉及到   向下滚动帐户。 Maybe this can help.

3)将元素滚动到视图中

使用Element.scrollIntoView,您可以将元素滚动到视图中,以便用户可以看到它。我选择添加&#34; smooth&#34;滚动下方,但您可以使用其他选项。查看文档。

function scrollElementIntoView(direction) {
    const next = calculateNextElement(direction);
    next.scrollIntoView({
        behaviour: "smooth"
    });
}

4)捕捉垂直滑动鼠标移动

这个看起来有点棘手。如果您习惯使用库,则可以使用HammerJS之类的内容。

基本上它归结为在mousedown上捕获鼠标然后再在mouseup上捕获鼠标,检查鼠标在两个事件之间移动了多少像素。我还建议检查两点之间的移动速度。

这是一次尝试:

let previousEvent;
let time;

// Keep track of the position where the user starts dragging
document.addEventListener("mousedown", function(event) {
    previousEvent = event;
    time = new Date();
});

// When the mouse is released, figure out which direction the mouse went
document.addEventListener("mouseup", function(event) {
    const pixelsY = previousEvent.screenY - event.screenY;
    const timeTaken = Date.now() - time.getTime();
    const speed = pixelsY / timeTaken;

    let direction;
    if (speed > 1) {
        direction = "up";
    } else if (speed < -1) {
        direction = "down";
    } else {
        direction = "tap";
    }

    scrollElementIntoView(direction);
});
祝你好运!

答案 2 :(得分:2)

我认为这是你的答案。

&#13;
&#13;
let currentElement = 0,
  maxLength = $("div[id^='section']").length,
  changeSw = false;

$(document).ready(function() {
  var clicked = false,
    clickY;
  $(document).on({
    mousemove: function(e) {
      clicked && updateScrollPos(e);
    },
    mousedown: function(e) {
      clicked = true;
      changeSw = true;
      clickY = e.pageY;
    },
    mouseup: function() {
      clicked = false;
      changeSw = false;
      $("html").css("cursor", "auto");
    }
  });

  var updateScrollPos = function(e) {
    $("html").css("cursor", "row-resize");
    // $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY));
    if (changeSw && clickY - e.pageY > 0) {
      currentElement =
        (currentElement < maxLength - 1) ? currentElement + 1 : currentElement;
      changeSw = false;
      clicked = false;
    } else if (changeSw && clickY - e.pageY <= 0) {
      currentElement = currentElement > 0 ? currentElement - 1 : 0;
      changeSw = false;
      clicked = false;
    }
    console.log(currentElement)
    $("html, body").animate({
        scrollTop: $("#section-" + currentElement).offset().top
      },
      200
    );

  };

  $(document).on("mousewheel", function(e) {
    if (e.originalEvent.wheelDelta > 0) {
      currentElement = currentElement > 0 ? currentElement - 1 : 0;

      $("html, body").animate({
          scrollTop: $("#section-" + currentElement).offset().top
        },
        200
      );
    } else {
      currentElement =
        currentElement < maxLength - 1 ? currentElement + 1 : currentElement;
      $("html, body").animate({
          scrollTop: $("#section-" + currentElement).offset().top
        },
        200
      );
    }
  });
});
&#13;
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="section-0">Section 1</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-1">Section 2</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-2">Section 3</div>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <br>
  <div id="section-3">Section 4</div>
</body>

</html>
&#13;
&#13;
&#13;