点击事件仍然在 div 下面触发
click event still triggered underneath div
这是我正在构建的 PhoneGap 应用程序,我正在笔记本电脑上进行测试,然后使用 PhoneGap cli 在 iphone 上进行测试。我有一张 openlayers 3 地图,上面记录了点击事件。我还有一个 div 可以在显示菜单时屏蔽整个地图。这个想法是当这个掩码 div 是 clicked/tapped 它隐藏自己但是下面的地图没有注册点击事件。正在发生的事情是地图正在注册点击事件,因此屏蔽 div 被隐藏但是地图随后做了其他事情,因为它被点击了,除了它不应该被点击!
我已将我的代码简化到细节。这是不显示和显示菜单和屏蔽 div 的两个屏幕截图。右下角的按钮是打开菜单的按钮 (.layers_menu_button
)。
这会在掩码 div (#net_curtain2
) 上侦听 clicks/taps,然后将其隐藏(请注意,注释掉的传播内容是我试图阻止 click/tap 事件,但它没有任何区别)。 interaction_type
定义为 click
或 touchend
,具体取决于我正在测试的内容。
$(window).on("load", function() {
$(document).on(interaction_type, "#net_curtain2", function(event) {
// event.stopImmediatePropagation();
hide_layers_menu();
});
setup_map();
});
...
function hide_layers_menu() {
$('.layers_menu_button').fadeIn("fast", function() {
// Animation complete
});
// remove hide class, add show class
$('.layers_menu_button').removeClass('hide_layers_menu');
$('.layers_menu_button').addClass('show_layers_menu');
$('.layers_menu_content').hide();
$("#net_curtain2").fadeOut("fast", function() {
// Animation complete
});
var layers_menu_width = parseInt($(window).width()-60);
$("#layers_menu").animate({
bottom: "30px",
right:"30px",
width: "20px",
height: "20px"
}, 'fast', function() {
// Animation complete
});
}
function setup_map() {
// create view
view = new ol.View({
center: ol.proj.transform([0.153733491897583, 52.655333117999774], 'EPSG:4326', 'EPSG:3857'),
zoom: 17
});
// create layers of map types
road = new ol.layer.Tile({
source: new ol.source.BingMaps({
imagerySet: 'Road',
key: 'my_key_here',
disableZooming: true,
maxZoom: 19
})
});
map = new ol.Map({
target: $('#map')[0],
layers: [
road
],
view: view,
controls : ol.control.defaults({
attribution:false,
zoom:false,
rotate: false
})
});
// check if net_curtain is visible and only act if NOT
map.on('click', function(evt) {
if($('#net_curtain2').is(':hidden'))
{
console.log("net curtain hidden");
}
else
{
console.log("net curtain showing");
}
});
var interactions = map.getInteractions().getArray();
var pinchRotateInteraction = interactions.filter(function(interaction) {
return interaction instanceof ol.interaction.PinchRotate;
})[0];
pinchRotateInteraction.setActive(false);
}
所以如果您在菜单未显示时单击地图,控制台会注销 'net curtain hidden',这是正确的。但是,如果您打开菜单,然后单击掩蔽 div(网幕),它会关闭菜单并隐藏网幕,这是正确的,但随后会触发 'net curtain hidden',这是错误的!我需要它停止隐藏窗帘。
最令人沮丧的是它可以在我的笔记本电脑上运行,但不能在 phone 上运行。将 map.on('click'...
更改为 map.on(interaction_type...
意味着它不会触发地图上的任何 click/tap 事件。我很困惑。
我相信您的移动浏览器正在尝试模拟点击事件。
致电 event.preventDefault();
应该可以解决您的问题。
试试代码:
$(document).on(interaction_type, "#net_curtain2", function(event) {
event.preventDefault();
hide_layers_menu();
});
解释:
我认为您的问题是移动浏览器模拟点击事件的方式。在为移动浏览器开发时要始终记住的一件事是,如果没有明确阻止默认操作,它们 会尝试模拟点击事件 。事件的顺序是这样的:
- 触摸启动
- 触摸移动
- 触摸端
- 鼠标悬停
- 鼠标移动
- 鼠标按下
- 鼠标弹起
- 点击
因此,通过在任何 touch
事件中不调用 event.preventDefault()
,您的移动浏览器假定您希望它继续通过该事件链,直到它触发 click
事件(就是这个click
给您带来问题的事件)。
这可能会造成混淆,因为调用 event.stopPropagation()
会阻止事件在事件链中向上冒泡 - 这是人们自然会假设正在发生的事情。但是您应该始终记住在触摸事件处理程序中使用 preventDefault(),这样默认的鼠标模拟处理就不会发生。
如需更深入的解释,read this。
可能相关:link
这是我正在构建的 PhoneGap 应用程序,我正在笔记本电脑上进行测试,然后使用 PhoneGap cli 在 iphone 上进行测试。我有一张 openlayers 3 地图,上面记录了点击事件。我还有一个 div 可以在显示菜单时屏蔽整个地图。这个想法是当这个掩码 div 是 clicked/tapped 它隐藏自己但是下面的地图没有注册点击事件。正在发生的事情是地图正在注册点击事件,因此屏蔽 div 被隐藏但是地图随后做了其他事情,因为它被点击了,除了它不应该被点击!
我已将我的代码简化到细节。这是不显示和显示菜单和屏蔽 div 的两个屏幕截图。右下角的按钮是打开菜单的按钮 (.layers_menu_button
)。
这会在掩码 div (#net_curtain2
) 上侦听 clicks/taps,然后将其隐藏(请注意,注释掉的传播内容是我试图阻止 click/tap 事件,但它没有任何区别)。 interaction_type
定义为 click
或 touchend
,具体取决于我正在测试的内容。
$(window).on("load", function() {
$(document).on(interaction_type, "#net_curtain2", function(event) {
// event.stopImmediatePropagation();
hide_layers_menu();
});
setup_map();
});
...
function hide_layers_menu() {
$('.layers_menu_button').fadeIn("fast", function() {
// Animation complete
});
// remove hide class, add show class
$('.layers_menu_button').removeClass('hide_layers_menu');
$('.layers_menu_button').addClass('show_layers_menu');
$('.layers_menu_content').hide();
$("#net_curtain2").fadeOut("fast", function() {
// Animation complete
});
var layers_menu_width = parseInt($(window).width()-60);
$("#layers_menu").animate({
bottom: "30px",
right:"30px",
width: "20px",
height: "20px"
}, 'fast', function() {
// Animation complete
});
}
function setup_map() {
// create view
view = new ol.View({
center: ol.proj.transform([0.153733491897583, 52.655333117999774], 'EPSG:4326', 'EPSG:3857'),
zoom: 17
});
// create layers of map types
road = new ol.layer.Tile({
source: new ol.source.BingMaps({
imagerySet: 'Road',
key: 'my_key_here',
disableZooming: true,
maxZoom: 19
})
});
map = new ol.Map({
target: $('#map')[0],
layers: [
road
],
view: view,
controls : ol.control.defaults({
attribution:false,
zoom:false,
rotate: false
})
});
// check if net_curtain is visible and only act if NOT
map.on('click', function(evt) {
if($('#net_curtain2').is(':hidden'))
{
console.log("net curtain hidden");
}
else
{
console.log("net curtain showing");
}
});
var interactions = map.getInteractions().getArray();
var pinchRotateInteraction = interactions.filter(function(interaction) {
return interaction instanceof ol.interaction.PinchRotate;
})[0];
pinchRotateInteraction.setActive(false);
}
所以如果您在菜单未显示时单击地图,控制台会注销 'net curtain hidden',这是正确的。但是,如果您打开菜单,然后单击掩蔽 div(网幕),它会关闭菜单并隐藏网幕,这是正确的,但随后会触发 'net curtain hidden',这是错误的!我需要它停止隐藏窗帘。
最令人沮丧的是它可以在我的笔记本电脑上运行,但不能在 phone 上运行。将 map.on('click'...
更改为 map.on(interaction_type...
意味着它不会触发地图上的任何 click/tap 事件。我很困惑。
我相信您的移动浏览器正在尝试模拟点击事件。
致电 event.preventDefault();
应该可以解决您的问题。
试试代码:
$(document).on(interaction_type, "#net_curtain2", function(event) {
event.preventDefault();
hide_layers_menu();
});
解释:
我认为您的问题是移动浏览器模拟点击事件的方式。在为移动浏览器开发时要始终记住的一件事是,如果没有明确阻止默认操作,它们 会尝试模拟点击事件 。事件的顺序是这样的:
- 触摸启动
- 触摸移动
- 触摸端
- 鼠标悬停
- 鼠标移动
- 鼠标按下
- 鼠标弹起
- 点击
因此,通过在任何 touch
事件中不调用 event.preventDefault()
,您的移动浏览器假定您希望它继续通过该事件链,直到它触发 click
事件(就是这个click
给您带来问题的事件)。
这可能会造成混淆,因为调用 event.stopPropagation()
会阻止事件在事件链中向上冒泡 - 这是人们自然会假设正在发生的事情。但是您应该始终记住在触摸事件处理程序中使用 preventDefault(),这样默认的鼠标模拟处理就不会发生。
如需更深入的解释,read this。
可能相关:link