【问题标题】:jquery preventing hover function on touchjquery防止触摸悬停功能
【发布时间】:2013-01-01 13:35:54
【问题描述】:

我有一个悬停功能,如果它是一个触摸设备,我希望悬停事件不会发生。问题是当您使用触摸设备点击链接时,它会在执行点击事件之前执行悬停事件,因此您必须点击它两次才能使其工作。

这是悬停功能:

$("#close").hover( 
    function () { 
        $("#close_2").css({
            display: "none"
        });
        $("#close_1").css({
            display: "block"
        });
    }, 
    function () {
        $("#close_1").css({
            display: "none"
        });
        $("#close_2").css({
            display: "block"
        });;
    }
); 

然后我将其设置为点击功能:

$('#close').click(function() {
    var id = $(this).attr('id');
    $('#full_image').animate({
        height: 0
    }, 300, function() {
        $('#full_image img').attr('src','#');
    });
    $("#close_1").css({
        display: "none"
    });
    $("#close_2").css({
        display: "none"
    });
    $("#close").css({
        display: "none"
    });
});

【问题讨论】:

  • 尝试 event.preventDefault() 悬停。 api.jquery.com/event.preventDefault
  • 嗯,你会怎么把它写进去?
  • @Mihir 这不会阻止方法执行,也不会阻止指定的处理程序运行。它可以防止 default 操作,就像名称所暗示的那样,这不是所描述的问题。
  • 好的,抱歉我误会了。您无法检测设备是否为触摸设备?如果是,则不要调用该函数。

标签: jquery click jquery-hover


【解决方案1】:

使 .hover() 方法更明确,并与 .on() 结合:

var $close1 = $('#close_1'),
    $close2 = $('#close_2');

$('#close').on({
    mouseenter: function(){
        $close2.css({display:'none'});
        $close1.css({display:'block'});
    },
    mouseleave: function(){
        $close1.css({display:'none'});
        $close2.css({display:'block'});
    }
});

然后将它与 .off() 结合起来。

$('#close').on('touchstart',function(){
    $(this).off('mouseenter,mouseleave');
});

如果您希望事件在点击触摸设备时触发,但在桌面设备上悬停时触发,则将函数作为您在这些操作中分别调用的单独函数。

编辑

自从我回答这个问题以来已经有一段时间了,这里有一个更好的方法:

$(function(){
    var isTouchDevice = ('ontouchstart' in window || 'onmsgesturechange' in window),
        $close = $('#close'),
        $close1 = $('#close_1'),
        $close2 = $('#close_2');

    if(!isTouchDevice){
        $close.on({
            mouseenter: function(){
                $close2.hide();
                $close1.show();
            },
            mouseleave: function(){
                $close1.hide();
                $close2.show();
            }
        });
    }

    $close.on('click',function(){
        $('#full_image').animate({height:0},300,function(){
            $(this).find('img').attr('src','#');
        });

        $close.hide();
        $close1.hide();
        $close2.hide();
    });
});

这不需要在每次触摸时触发“防止悬停”事件,基本上是在不影响点击事件的情况下设置页面加载功能。

【讨论】:

  • 特别指定 'mouseenter' 和 'mouseleave' 应该没有什么不同,因为 hover 只是它的简写;第二种方法似乎应该可以工作。 +1
  • hmm,所以我在上面发布的悬停代码中添加了那个小片段,当我点击触摸屏时,它仍然首先执行悬停事件,然后再次点击并执行点击事件。
  • @lifeinthegrey 在这里您可以实际尝试拼写方法,速记悬停现在仅用作方法,不推荐使用伪事件,因此它在 1.8+ 中不起作用。 $('#close').off('mouseenter mouseleave');。只是一个想法。
  • 啊该死的,我有点怀疑,但我已经改了,不想再改了哈哈...代码已修改
【解决方案2】:

我认为一个明确的方法是:

  1. 检测浏览器是否支持触摸事件
  2. 相应地添加悬停事件处理程序

如果您已经在使用 Modernizr 之类的东西:

if(!Modernizr.touch){
    // only if the browser doesn't support touch events,
    // add the hover handler here.
}
//add the click handler here, as you want it bound no matter what

有关检测触摸功能的其他选项,请参阅 What's the best way to detect a 'touch screen' device using JavaScript?What's the best way to detect a 'touch screen' device using JavaScript?

【讨论】:

  • 这完全可行,但会增加引入库的完全不必要的开销。
  • ...这正是我说“如果您正在使用类似 Modernizr 已经之类的东西”的原因,并包含指向 SO 问题讨论的链接替代检测方法:)
【解决方案3】:

在移动端调用 touchstart 事件中的 preventDefault 可防止 mouseovermouseentermousedown em> 和附属活动。详情:https://patrickhlauke.github.io/touch/tests/results/

    $('#close').on('touchstart',function(e){
        console.log('touchstart');
        e.preventDefault();
        //Do touch stuff
    });

【讨论】:

  • 这正是我所需要的。谢谢。
  • 这个答案确实有效(这里的大多数答案不考虑具有触摸屏+鼠标的设备,如触摸屏笔记本电脑),也是最简单的答案。
【解决方案4】:

由于 Windows 8 和超极本,我希望看到很多设备同时支持触摸和指针事件。因此,我避免完全禁用悬停事件,因为它可能会破坏使用鼠标启用触摸的用户的网站。

为了解决这个问题,我最终使用了两个不同的类来显示菜单,.hover.touch,以及悬停和点击的单独事件。

我使用jquery.finger 来捕获点击事件,尽管任何插件都应该可以工作,这只是最小的一个。

HTML 应该是这样的:

<li>
    <a>Some Link</a>
    <div>Some Content</div>
</li>

CSS 类似于:

li div {display:none;}
li.hover div, li.touch div {display:block;}

以及使用 JQuery 的 Javascript:

// Caching whatever elements I'm using for the navigation
a = $("a");
li = $("li");

// Set hover events
li.hover(

    // Both hover in and out fire whenever the user taps, aggravating!
    function(e) {
        // Close unused menus
        li.not(this).removeClass("hover").removeClass("touch");

        // Show this menu
        $(this).addClass( "hover" );
    }, function(e) {
        // Only closes if the menu doesn't have .touch, hell yeah!
        li.removeClass("hover");
    }

);

// Set the tap event
a.on('tap',function(e,data){
    e.stopPropagation();
    var thisParent = $(this.parentNode);

    // Close unused menus
    li.not(thisParent).removeClass("touch");

    // Toggle the current menu
    thisParent.toggleClass("touch");

    // The menu is open, so we don't need this class anymore
    li.removeClass("hover");
});

// Prevent the list items when being tapped from closing the drop down
li.on('tap',function(e){e.stopPropagation();});

// Close drop downs when tapping outside the menus
$(document).on('tap',function(e){
   li.removeClass("touch");
});

这里重要的一点是我如何根据事件添加单独的 .hover.touch 类,以及删除未使用的类。顺序很重要,所以菜单不会闪烁。

【讨论】:

    【解决方案5】:

    最终使用了触摸检测:

    var deviceAgent = navigator.userAgent.toLowerCase();
    var agentID = deviceAgent.match(/(iphone|ipod|ipad)/);
    
    if(agentID) { 
        $('#close').click(function() {
            var id = $(this).attr('id');
            $('#full_image').animate({
                height: 0
            }, 300, function() {
                $('#full_image img').attr('src','#');
            });
            $("#close_1").css({
                display: "none"
            });
            $("#close_2").css({
                display: "none"
            });
            $("#close").css({
                display: "none"
            });
        });
    }
    else {
        $('#close').hover(
            function() {
                $("#close_2").css({
                    display: "none"
                });
                $("#close_1").css({
                    display: "block"
                });
            }, function() {
                $("#close_1").css({
                    display: "none"
                });
                $("#close_2").css({
                    display: "block"
                });
            }
        ); 
        $('#close').click(function() {
            var id = $(this).attr('id');
            $('#full_image').animate({
                height: 0
            }, 300, function() {
                $('#full_image img').attr('src','#');
            });
            $("#close_1").css({
                display: "none"
            });
            $("#close_2").css({
                display: "none"
            });
            $("#close").css({
                display: "none"
            });
        });
    }
    

    【讨论】:

    • 不是触摸检测。是检测“如果用户是苹果的粉丝”。为什么这是公认的答案?
    猜你喜欢
    • 1970-01-01
    • 2011-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    • 1970-01-01
    相关资源
    最近更新 更多