这可能是一个愚蠢的问题。我知道我有点绿。 我的任务是修改旧的旧系统导航。有两个导航栏。第二个只有搜索按钮。我被要求删除第二个导航栏,并将其替换为显示搜索功能的下拉列表。由于这个系统的年龄,我受限于我能改变的地方。我可以写的JS没有限制。他们在Adobe ColdFusion系统上运行jQuery 1.11.1(两个月前他们从1.3.2升级)
首先:单击目标时,mouseenter和click事件都会触发。 mouseenter首先开火。这会导致桌面上的问题对敏锐的查看者可见,但在移动设备上,这会产生可怕的可用性问题。答:根据我的理解,鼠标事件不会发生在移动设备上,而是适用于我。 B:由于mouseenter事件首先运行,它会在处理click事件之前激活closeDropDown函数。在closeDropDown运行时,其.on('click', f(...eventstuff...))
会听到旨在触发openDropDown函数的打开点击,因此下拉列表无法打开。
这是功能。 console.log
用于检查何时运行。
function openDropDown(){
$('div.dropdown').parent().on('click.open mouseenter', function(event){
$subject = $(this).find('.dropdown-menu')
// console.log(event.type, $subject, "first o");
if(!$subject.is(":visible")){
// console.log($subject, 'second o');
$subject.show()
}else {
if(event.type == 'click'){
// console.log('third o');
$subject.toggle()
}
}
closeDropDown($subject)
// console.log('open complete');
})
}
function closeDropDown($x){
// console.log('first c');
$(document).on("click.close",function(e){
// console.log("second c", e.type, "this type");
if(!$(e.target).closest(".dropdown-menu").parent().length){
// console.log("third c");
if($x.is(":visible")){
// console.log('forth c');
$x.hide()
}
}
$(document).off("click.close")
// console.log('complete close');
})
}
openDropDown()
onSearchClick()
总之,我知道我需要压缩我的代码。我理解了一些解决此问题的方法(添加if(... are we on a mobile device...)
或一些计数器/检查,以防止在关闭下拉列表时运行closeDropDown)
我真的想了解事件监听器的基本原理以及为什么在其他东西之前运行。
虽然有关如何解决这个问题的建议很好,但我希望了解我做错的基本原理。任何基本指针都非常有用。
值得注意的是:我刚看过这个:.is(':visible') not working。我将使用.is重写代码('可见')。
其他可能有用的事情: 当我的所有console.log都处于活动状态时,这是Chrome Dev Tools控制台。 首先,点击页面加载后.... 下拉打开并快速关闭。
谢谢!感谢您的所有帮助!
答案 0 :(得分:2)
这是一个非常广泛的问题。我会尝试简洁。我不认为ColdFusion
应该在这里标记,因为它似乎只与HTML / CSS / JS有关。
配置活动
首先,我想解决您配置脚本的方式。 您可能会从查看事件处理examples from jquery中受益。
大多数人都会创建如下事件。它只是说,点击任何ID为" alerter"的文档元素,运行警报功能。
// Method 1
$(document).on(click, "#alerter", function(event){
alert("Hi!");
});
OR
// Method 2
$(document).on("click", "#alerter", ClickAlerter);
function ClickAlerter(event) {
alert("Hi!");
}
这两种方法都是完全有效的。但是,我的意见第二种方法更具可读性和可维护性。它将事件委托与逻辑分开。
对于您的代码,我强烈建议删除事件分配和逻辑的混合。 (它至少删除了一层嵌套)。
顺便说一下,您的事件监听器似乎没有正确配置。请参阅jQuery中的the correct syntax和此示例。
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});
关于多项活动
如果对象上有多个事件侦听器,则它们将按照它们注册的顺序触发。 This SO question已经涵盖了这一点,并提供了一个示例。
然而,这并不意味着在鼠标中心之前会发生点击。因为鼠标必须逐字输入才能单击它,所以将首先触发mouseenter事件。换句话说,在考虑事件的顺序时,你至少有两个因素在起作用。
因此,并没有像#34;同时"事件,本身。当浏览器想要触发事件时会触发事件,并且它们将按照您分配的顺序浏览事件并触发匹配。
如果要更改默认事件行为,则始终可以选择preventDefault和stopPropagation这些事件。这将停止浏览器的默认操作,并防止事件分别冒泡到父元素。
关于移动鼠标事件
鼠标事件绝对发生在移动设备上,并且假设它们没有安全性是不安全的。 This article深入介绍了被解雇事件的范围。引用:
" [Y]在设计更高级的触摸交互时必须要小心:当用户使用鼠标时,它将通过点击事件进行响应,但是当用户触摸屏幕时,将发生触摸和点击事件。只需单击一下,事件的顺序为:
touchstart touchmove touchend mouseover mousemove mousedown mouseup click
我认为你会从阅读那篇文章中受益。它涵盖了有关移动和非移动环境中事件的常见问题和概念。再次,关于你的情况的相关陈述:
有趣的是,在某些情况下,CSS:悬停伪类可以由触摸界面触发 - 点击一个元素使它:在手指关闭时处于活动状态,并且它还获得:悬停状态。 (使用Internet Explorer时,:悬停仅在用户手指关闭时生效 - 其他浏览器保持:悬停生效,直到下一次点击或鼠标移动。)
示例
我采用了所有这些概念并made an example on jsFiddle向您展示了其中的一些实际操作。基本上,我通过侦听touchstart
事件并在这种情况下以不同方式处理click
来检测用户是否正在使用触摸屏。因为我没有HTML,所以我必须创建一个原始界面。这些是指令:
正如您将看到的,我在一个地方创建了所有活动:
$(document).on("mouseover", "#open", $app.mouseOver);
$(document).on("mouseout", "#open", $app.mouseOut);
$(document).on("click", "#open", $app.click);
$(document).on("touchstart", $app.handleTouch);
$(document).on("touchstart", "#open", $app.click);
我还创建了一个对象来包装所有逻辑,$app
,这为我们提供了更大的灵活性和可读性。这是它的一个片段:
var $app = $app || {};
$app = {
hasTouchScreen: false,
handleTouch:function(e){
// fires on the touchstart event
$app.hasTouchScreen = true;
$("#hasTouchScreen").html("true");
$(document).off("touchstart", $app.handleTouch);
},
click: function(e) {
// fires when a click event occurrs on the button
if ($app.hasTouchScreen) {
e.stopPropagation();
e.preventDefault();
return;
}
// since we don't have a touchscreen, close on click.
$app.toggleMenu(true);
},
touch: function(e) {
// fires when a touchstart event occurs on the button
if ($("#menu").hasClass("showing")) {
$app.toggleMenu(true);
} else {
$app.toggleMenu();
}
}
};