阻止事件默认行为:event.preventDefault() 导致:hover伪类保持激活

3
我正在尝试实现一个文档导航,类似于Bootstrap网站上的文档导航。总体上,我已经实现了它,但有一点让我感到困扰。与Bootstrap一样,我正在使用affix.js和scrollSpy.js的组合,并且这是有效的。请参见以下JSFiddle
        $('#doc_nav').on( "click", "a", function( e ){
//            e.preventDefault();
            var target = this.hash;
            var $target = $(target);
            var offset = $target.offset().top;
            console.log(offset);
            offset = offset - 100;
            console.log(offset);

            $('html, body').scrollTop( offset );


        });

在注释掉e.preventDefault()的情况下,导航菜单的行为符合预期。向下滚动窗口会导致菜单上显示的div被突出显示。单击菜单列表中的项,将直接跳转到页面上相应的div,当您从页面上的该部分滚动时,菜单会相应更新。
在我的“真实”页面上,我有一个高度为100px的固定页眉。因此,当前,当我单击菜单链接时,页面会跳转到所需的部分,并将其放置在页面顶部,其中页眉略微遮挡它。上面的代码中的scrollTop部分似乎不起作用,除非我使用e.preventDefault()。如果您在fiddle中取消对此行的注释并再次运行它,请单击菜单上的“标题3”链接,您将看到它现在将“标题3”内容放在页面上,距离顶部偏移100px。完美。
但是,现在向上滚动页面,靠近顶部时,您会发现“标题3”列表项仍处于:hov状态,即使鼠标远离它也是如此。就好像e.preventDefault()已经阻止浏览器检测到鼠标不再悬停在该项上一样。
单击浏览器窗口外的任何位置,可以解决问题。

有人能解释一下我在这里做错了什么吗?我如何防止锚点点击的默认行为,以便控制页面滚动位置,同时不会停止正确的CSS绘画过程?

问题出现是因为我正在使用e.preventDefault()来阻止浏览器的默认行为,因为我想控制滚动到锚定元素。

我已在Firefox和IE10中进行了测试。

1个回答

6
问题不在于:hover状态,而是:focus状态。
当您点击链接时,该链接会获得焦点,因此应用了:focus样式(与您代码中的:hover样式相同)。通过防止默认行为,该链接保持活动状态并且不会失去焦点。
一个快速的解决方案是使用$(this).blur()取消元素的焦点/模糊状态。
在您的代码中,它看起来像这样:
    $('#doc_nav').on( "click", "a", function( e ){
        e.preventDefault();
        var target = this.hash;
        var $target = $(target);
        var offset = $target.offset().top;
        console.log(offset);
        offset = offset - 100;
        console.log(offset);
        $(this).blur();
        $('html, body').scrollTop( offset );
    });

您可以在此处查看演示:https://jsfiddle.net/z32rpe3b/30/


为什么使用 e.preventDefault() 时正常工作,而不使用却不正确?

答案与执行顺序有关。在浏览器中,onclick 事件发生在 href 重定向之前:

  • 如果没有使用 e.preventDefault(),则代码会执行,在 onclick 中浏览器正确地滚动到目标 offset - 100 位置,然后执行链接的 href 并滚动到目标 offset。它只是发生得非常快,以至于似乎直接跳转到目标位置。
  • 如果使用了 e.preventDefault(),则代码会执行(滚动到 offset - 100),浏览器不会执行 href 操作(因此停留在 offset - 100)。

嗨,阿尔瓦罗。谢谢。我很后悔这么简单!我一直固执地认为它是:hover伪类,错过了:focus。你能回答谜题的另一部分吗?为什么scrollTop()没有起作用,除非我使用了e.preventDefault()? - Boidy
1
这与事件执行的顺序有关。我更新了我的答案,并解释了发生这种情况的原因。 - Alvaro Montoro

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