问题
I have a hover function, if it's a touch device I'd like the hover event to NOT happen. The problem is when you tap the link with a touch device it does the hover event before doing the click event, so you have to tap it twice for it to work.
this is the hover function:
$("#close").hover(
function () {
$("#close_2").css({
display: "none"
});
$("#close_1").css({
display: "block"
});
},
function () {
$("#close_1").css({
display: "none"
});
$("#close_2").css({
display: "block"
});;
}
);
and then I have this set up as the click function:
$('#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"
});
});
回答1:
Make the .hover() method more explicit and combine it with .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'});
}
});
Then combine that with .off().
$('#close').on('touchstart',function(){
$(this).off('mouseenter,mouseleave');
});
If you want the event to fire on click with touch devices, but on hover on desktop devices, then put the functions as a separate function you call within those actions respectively.
EDIT
Been a while since I did this answer, here is a better way:
$(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();
});
});
This doesn't require a "hover prevention" event to fire with each touch, basically sets capabilities on page load while not affecting the click event.
回答2:
I think a clear approach would be to:
- Detect if the browser supports touch events
- Add the hover event handler accordingly
If you're using something like Modernizr already:
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
See What's the best way to detect a 'touch screen' device using JavaScript? and What's the best way to detect a 'touch screen' device using JavaScript? for other options to detect touch capabilities.
回答3:
On mobile side calling preventDefault in touchstart event prevents mouseover, mouseenter, mousedown and affiliated events. Detail: https://patrickhlauke.github.io/touch/tests/results/
$('#close').on('touchstart',function(e){
console.log('touchstart');
e.preventDefault();
//Do touch stuff
});
回答4:
Because of Windows 8 and Ultrabooks, I expect to see a lot of devices that support both touch and pointer events. As a result, I avoid disabling the hover event outright since it could potentially break the site for an touch enabled user with a mouse.
To solve this problem I ended up using two different classes for displaying menus, .hover
and .touch
, as well as separate events for hover and tap.
I'm using jquery.finger for capturing tap events, though any plug-in should work, this was just the smallest one.
The HTML Would be something like:
<li>
<a>Some Link</a>
<div>Some Content</div>
</li>
The CSS would be something like:
li div {display:none;}
li.hover div, li.touch div {display:block;}
And the Javascript using JQuery:
// 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");
});
The important take away here is how I'm adding a seperate .hover
or .touch
class depending on the event, as well as removing the unused classes. The order is important so the menus don't blink.
回答5:
ended up using touch detection:
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"
});
});
}
来源:https://stackoverflow.com/questions/14388813/jquery-preventing-hover-function-on-touch