jQuery如何防止在触摸设备上激活悬停函数

11

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

这是悬停函数:

$("#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()。http://api.jquery.com/event.preventDefault/ - Learner
哦,你会如何将它写入其中? - loriensleafs
@Mihir 这并不会阻止方法执行,也不会阻止指定的处理程序运行。它只是防止了默认操作,正如其名称所示,并不是所描述问题的原因。 - nbrooks
好的,抱歉我误解了。您能否不检测设备是否为触摸设备?如果是,则不调用该函数。 - Learner
5个回答

15

让 .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 - nbrooks
嗯,所以我把那段小代码片段加入了我上面发布的hover代码中,当我在触摸屏上轻敲时,它仍然会先执行hover事件,然后再轻敲一次才会执行点击事件。 - loriensleafs
@lifeinthegrey 这里是你可以尝试拼写方法的地方,现在悬停的简写只作为一种方法工作,伪事件的使用已被弃用,因此在1.8+中不起作用。$('#close').off('mouseenter mouseleave');这只是一个想法。 - nbrooks
啊,该死,我有点怀疑,但我已经改过了,不想再改一遍哈哈... 代码重新修改。 - PlantTheIdea

5
我认为一个清晰的方法是:
  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

请参考 如何使用JavaScript检测“触摸屏”设备的最佳方法?如何使用JavaScript检测“触摸屏”设备的最佳方法? 以了解其他检测触摸功能的选项。


这个完全可行,但是引入一个库会增加完全不必要的开销。 - PlantTheIdea
4
这就是我说“如果你已经在使用类似Modernizr的东西”的原因,并附上了讨论替代检测方法的StackOverflow问题链接 :) - freethejazz

3
在移动端,调用touchstart事件中的preventDefault会阻止mouseovermouseentermousedown以及相关事件。详情请见:https://patrickhlauke.github.io/touch/tests/results/
    $('#close').on('touchstart',function(e){
        console.log('touchstart');
        e.preventDefault();
        //Do touch stuff
    });

这正是我所需要的。谢谢。 - Graham P Heath
这个答案实际上是可行的(大多数答案都没有考虑到具有触摸屏和鼠标的设备,比如触摸屏笔记本电脑),而且也是最简单的答案。 - Skeets

2
由于Windows 8和Ultrabooks,我预计会看到很多支持触摸和指针事件的设备。因此,我避免完全禁用悬停事件,因为这可能会破坏对使用鼠标的触摸启用用户的网站。
为了解决这个问题,我最终使用了两个不同的类来显示菜单,.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"
        });
    });
}

2
这不是触摸检测。而是检测“用户是否是苹果的粉丝”。为什么这是被接受的答案? - Maciej Paprocki

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