【问题标题】:Mousemove / scroll to next hash鼠标移动/滚动到下一个哈希
【发布时间】:2018-10-22 04:22:43
【问题描述】:

我添加了以下代码以便用鼠标滚动(点击+拖动滚动,而不是鼠标滚轮)。到目前为止,一切都很好 - 就像一个魅力:

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();

});

【问题讨论】:

  • 感谢您的输入,但我认为它根本不是重复的,即使它可能包含有用的代码。我在这里尝试做的是重写我的鼠标单击滚动行为以滚动到哈希,而不仅仅是向上和向下滚动。

标签: javascript jquery html


【解决方案1】:

我看到一些你必须解决的事情:

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

在您想要滚动到的元素上放置诸如 ID 属性或类之类的内容。除了新的导航方法外,您还可以使用 ID 属性使用老式哈希 URL 导航 (http://some-url/#some-anchor)。

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

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

querySelectorAll 不返回 Element 数组,而是返回一个 节点列表。您可以使用将其转换为数组 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,您可以将元素滚动到视图中,以便用户可以看到它。我选择在下面添加“平滑”滚动,但您可以使用其他选项。检查文档。

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);
});

祝你好运!

【讨论】:

  • 截取的问题允许单击并沿任意方向拖动(向上或向下几个像素)。当侦听器注意到单击和向下滚动行为时,我试图自动跳转到最近的哈希/部分到底部,并在单击向上滚动时自动跳转到最近的哈希/部分到顶部移动。知道如何重写代码来实现这一目标吗?还是您的代码只是因为我未能正确实现它?
  • 我写下的代码并没有做到这一点。然而,我想我已经给了你大部分的谜题。你应该能够弄清楚:)
  • 您的代码本身并没有考虑任何拖动行为,对吧?它也是用 JS 编写的,而上面的片段是 JQuery。我仍然是初学者,即使我了解您的代码的作用,我也无法将原始片段重写为 JS。
  • 哦,好吧。您的意思类似于当您想要滚动时如何在移动设备上轻弹屏幕?为此,您需要扩展鼠标侦听器的功能。
  • 没错。我已经准备好代码(在发布上面的答案之前)跳转到鼠标滚轮触发器上的下一个哈希。最重要的是,我添加了上面发布的代码,允许用鼠标单击和拖动。我想单击>按住>向一个方向拖动>“拖动10px后跳转到下一个哈希”。我认为可以修改 mousemove 行为来解决这个问题。
【解决方案2】:

我想这就是你的答案。

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
      );
    }
  });
});
<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>

【讨论】:

  • 非常感谢。我使用的鼠标滚轮代码对我来说效果更好,但其余的正是我想要的。非常感谢!我将鼠标滚轮代码添加到我的问题中,以防您想查看。
  • 在触发跳转之前,我如何添加一个条件,该条件要求在任一方向上至少拖动 100 像素?
  • 我认为将clickY - e.pageY &gt; 0 更改为clickY - e.pageY &gt; 100 可以解决这个问题。检查。祝你好运。
  • 不是这样,但我会试着弄清楚。谢谢!
【解决方案3】:

希望对你有帮助

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>

【讨论】:

  • 很棒的代码,但不是我想要的。我得到了这个功能加上我在我的问题中发布的那个。我想要做的是修改我在问题中包含的代码,以便在单击+拖动时跳转到下一个哈希,而不是向上滚动几个像素。
  • 拖动和移动确实是我需要的,谢谢!理想情况下,我想将最后一点添加到我现有的代码中,而不是用这个 fullPage 代码全部替换。
猜你喜欢
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多