jQuery 事件委托不适用于 jQuery UI 日期选择器
jQuery event delegation is not working on jQuery UI datepicker
我试图阻止特定的点击事件冒泡到文档根目录,结果关闭了我的一个弹出窗口。我需要停止冒泡事件,body
或 html
是我拦截和停止它的唯一选择。
日期选择器弹出窗口是即时生成的,所以我不能在 .ui-icon
元素上使用直接事件,所以我在 body
元素上注册了一个委托事件以阻止它冒泡。
(function ($) {
$(function () {
$('body').on('click', '.ui-icon', function (e) {
e.stopPropagation();
});
});
})(jQuery);
令人惊讶的是,将直接事件注册到 body
元素并检查事件的目标工作得很好。
(function ($) {
$(function () {
$('body').on('click', function (e) {
if ($(e.target).is('.ui-icon')) {
e.stopPropagation();
}
});
});
})(jQuery);
我真的很纳闷,为什么前一个不行,后一个不行,这两个应该是一样的。我错过了什么?这可能与 jQuery 在事件到达正文之前重新组合日期选择器(其整个内容块在导航上重建)有关(但这没有意义)?
下面添加了包含问题的代码段。我只希望箭头(日期选择器导航)停止冒泡到 document/root 级别(这会关闭我的弹出窗口)并且因为日期选择器附加到主体,唯一可用的拦截点是 body/html.
$(function() {
let popup = $('#some-popup').addClass('visible');
let input = $('#some-date');
let toggler = $('#toggler');
// binding popup
toggler.on('click', function(e) {
e.stopPropagation();
popup.toggleClass('visible');
});
// initializing jQuery UI datepicker
input.datepicker();
// closing popup on document clicks other than popup itself
$(document).on('click', function(e) {
let target = $(e.target);
if (target.is('.ui-icon, .ui-datepicker-prev, .ui-datepicker-next')) {
console.warn('shouldn\'t have reached this, got: ' + target.attr('class'));
}
if (!(target.is('#some-popup'))) {
popup.removeClass('visible');
}
});
// trying to prevent click from reaching document
$('body').on('click', '.ui-icon, .ui-datepicker-prev, .ui-datepicker-next', function(e) {
e.stopPropagation();
})
});
#some-popup {
padding: 15px 25px;
background: #000;
color: #fff;
display: none;
max-width: 200px;
}
#some-popup.visible {
display: block;
}
#toggler {
margin-bottom: 10px;
}
<head>
<link href="https://code.jquery.com/ui/1.11.4/themes/black-tie/jquery-ui.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>
<body>
<div id="some-popup">
This is the popup
</div>
<button type="button" id="toggler">Show/Hide Popup</button>
<form>
<label for="some-date">The Date-Picker</label>
<input id="some-date" onclick="event.stopPropagation();" />
</form>
</body>
委托事件不会触发,因为当您单击箭头时,首先会触发箭头按钮的单击事件,其中 jquery-ui-datepicker 从 body
元素中删除整个日历元素并生成一个新的previous/next 个月的日历。
您可以通过检查元素是否具有任何父 <body>
标记来验证元素是否被删除,即通过检查 closest('body')
.
的长度
$('body').on('click', function (e) {
if ($(e.target).is('.ui-icon')) {
console.log($(e.target).closest('body').length);
// Prints 0 i.e this element is not a child of <body>
}
});
要触发委托事件,目标元素必须是事件绑定元素的子元素,否则jQuery不会触发事件。下面的Demo证实了这一点。
$(function() {
$('.a').on('click', function() {
console.log('Direct Event');
})
$('.a').on('click', '.b,.c', function(e) {
console.log('Delegate Event');
})
$('.b').on('click', function() {
console.log('datepicker arrow event');
if($('input').is(':checked')) $(this).remove();
})
});
.a {
padding: 20px;
background: #ffc55a;
text-align: center;
}
.b {
margin-top: 5px;
padding: 5px;
background: #7ddbff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="a">
This is the parent element (Delegate Bound Element)
<div class="b">
This is the Arrow element of date-picker (Delegate Target)<br>
Click on it to see how many events fire
</div>
</div>
<input type="checkbox" checked> Remove On<br>
With Remove Off 3 events fire<br>
With Remove On 2 events fire, Delegate event does not fire<br>
我试图阻止特定的点击事件冒泡到文档根目录,结果关闭了我的一个弹出窗口。我需要停止冒泡事件,body
或 html
是我拦截和停止它的唯一选择。
日期选择器弹出窗口是即时生成的,所以我不能在 .ui-icon
元素上使用直接事件,所以我在 body
元素上注册了一个委托事件以阻止它冒泡。
(function ($) {
$(function () {
$('body').on('click', '.ui-icon', function (e) {
e.stopPropagation();
});
});
})(jQuery);
令人惊讶的是,将直接事件注册到 body
元素并检查事件的目标工作得很好。
(function ($) {
$(function () {
$('body').on('click', function (e) {
if ($(e.target).is('.ui-icon')) {
e.stopPropagation();
}
});
});
})(jQuery);
我真的很纳闷,为什么前一个不行,后一个不行,这两个应该是一样的。我错过了什么?这可能与 jQuery 在事件到达正文之前重新组合日期选择器(其整个内容块在导航上重建)有关(但这没有意义)?
下面添加了包含问题的代码段。我只希望箭头(日期选择器导航)停止冒泡到 document/root 级别(这会关闭我的弹出窗口)并且因为日期选择器附加到主体,唯一可用的拦截点是 body/html.
$(function() {
let popup = $('#some-popup').addClass('visible');
let input = $('#some-date');
let toggler = $('#toggler');
// binding popup
toggler.on('click', function(e) {
e.stopPropagation();
popup.toggleClass('visible');
});
// initializing jQuery UI datepicker
input.datepicker();
// closing popup on document clicks other than popup itself
$(document).on('click', function(e) {
let target = $(e.target);
if (target.is('.ui-icon, .ui-datepicker-prev, .ui-datepicker-next')) {
console.warn('shouldn\'t have reached this, got: ' + target.attr('class'));
}
if (!(target.is('#some-popup'))) {
popup.removeClass('visible');
}
});
// trying to prevent click from reaching document
$('body').on('click', '.ui-icon, .ui-datepicker-prev, .ui-datepicker-next', function(e) {
e.stopPropagation();
})
});
#some-popup {
padding: 15px 25px;
background: #000;
color: #fff;
display: none;
max-width: 200px;
}
#some-popup.visible {
display: block;
}
#toggler {
margin-bottom: 10px;
}
<head>
<link href="https://code.jquery.com/ui/1.11.4/themes/black-tie/jquery-ui.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
</head>
<body>
<div id="some-popup">
This is the popup
</div>
<button type="button" id="toggler">Show/Hide Popup</button>
<form>
<label for="some-date">The Date-Picker</label>
<input id="some-date" onclick="event.stopPropagation();" />
</form>
</body>
委托事件不会触发,因为当您单击箭头时,首先会触发箭头按钮的单击事件,其中 jquery-ui-datepicker 从 body
元素中删除整个日历元素并生成一个新的previous/next 个月的日历。
您可以通过检查元素是否具有任何父 <body>
标记来验证元素是否被删除,即通过检查 closest('body')
.
$('body').on('click', function (e) {
if ($(e.target).is('.ui-icon')) {
console.log($(e.target).closest('body').length);
// Prints 0 i.e this element is not a child of <body>
}
});
要触发委托事件,目标元素必须是事件绑定元素的子元素,否则jQuery不会触发事件。下面的Demo证实了这一点。
$(function() {
$('.a').on('click', function() {
console.log('Direct Event');
})
$('.a').on('click', '.b,.c', function(e) {
console.log('Delegate Event');
})
$('.b').on('click', function() {
console.log('datepicker arrow event');
if($('input').is(':checked')) $(this).remove();
})
});
.a {
padding: 20px;
background: #ffc55a;
text-align: center;
}
.b {
margin-top: 5px;
padding: 5px;
background: #7ddbff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="a">
This is the parent element (Delegate Bound Element)
<div class="b">
This is the Arrow element of date-picker (Delegate Target)<br>
Click on it to see how many events fire
</div>
</div>
<input type="checkbox" checked> Remove On<br>
With Remove Off 3 events fire<br>
With Remove On 2 events fire, Delegate event does not fire<br>