jquery防止触摸悬停功能

Posted

技术标签:

【中文标题】jquery防止触摸悬停功能【英文标题】:jquery preventing hover function on touch 【发布时间】: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 操作,就像名称所暗示的那样,这不是所描述的问题。 好的,抱歉我误会了。您无法检测设备是否为触摸设备?如果是,则不要调用该函数。 【参考方案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】:

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

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

如果您已经在使用 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"
        );
    );

【讨论】:

不是触摸检测。是检测“如果用户是苹果的粉丝”。为什么这是公认的答案?

以上是关于jquery防止触摸悬停功能的主要内容,如果未能解决你的问题,请参考以下文章

如何防止触摸设备上按钮的粘滞悬停效果

如何防止触摸设备上按钮的粘滞悬停效果

JQuery Animate - 如何在悬停后立即停止悬停功能(不要完成悬停功能)

结合悬停和单击功能(jQuery)?

如何防止我的触摸设备执行 ::hover 而不是点击功能?

jQuery悬停功能 - 我错过了啥?