Javascript 侦听数组中对象的更改,而不嵌套事件侦听器
(免责声明:这个问题比标题所暗示的要简单得多!) 在我的程序体系结构中,我有一个反复出现的问题,就是监听对模型的更改 我设置了一些集合(很像Javascript 侦听数组中对象的更改,而不嵌套事件侦听器,javascript,jquery,event-bubbling,event-listener,Javascript,Jquery,Event Bubbling,Event Listener,(免责声明:这个问题比标题所暗示的要简单得多!) 在我的程序体系结构中,我有一个反复出现的问题,就是监听对模型的更改 我设置了一些集合(很像Backbone.js),它们只是围绕数组构建的轻量级类。集合是模型的集合。当用户对模型进行更改时,我总是以可怕的嵌套事件结束。这是我试图避免的典型、简单的场景: $("#user-details").on("click", "#save", onSaveClick); function onSaveClick() { var giv
Backbone.js
),它们只是围绕数组构建的轻量级类。集合是模型的集合。当用户对模型进行更改时,我总是以可怕的嵌套事件结束。这是我试图避免的典型、简单的场景:
$("#user-details").on("click", "#save", onSaveClick);
function onSaveClick()
{
var givennames = $("#givenname").val(),
// Get the model from the collection
var user = users.get($(this).attr("data-id"));
// set the property
user.set("GivenNames", givennames);
// listen for the save event
$(user).on("save", function(){
// Alert the view
});
user.save(); // save event triggers a "save" event on the model
}
如果同一用户保存两次,则会多次添加/触发事件。有更好的模式吗
该事件是否应该在集合中不断涌现并以这种方式处理
下面是一个实际的例子(我最为惭愧的例子)
您只需检查
save
事件是否已绑定,在这种情况下,不要再次绑定它,如下所示:
// if no 'save' event already binded
if (!$(user).data('events') || !$(user).data('events').save) {
// listen for the save event
$(user).on("save", function(){
// Alert the view
});
}
$("#user-devices").on("click", ".device button", function(){
var button = $(this),
deviceId = $(this).closest(".device").attr("data-id"),
device = userDevices.get(deviceId);
if (device.get("Active") === "1")
{
$("#reactivation-warning-dialog").modal("show");
$("#reactivation-warning-dialog .btn-primary").on("click", device.activate);
}
else
{
device.activate();
}
});
//in the device "class"
{
...
...
activate: function() {
//persist and stuf.
//on success...
this.render();
}
render: function() {
button.removeClass("btn-danger").addClass("btn-success");
$("#activation-dialog").modal("show");
}
}
见工作
为了在上面添加一些糖分,我们可以将“检查事件是否存在””逻辑放入自定义jquery伪选择器中,其定义如下:
$.expr[':'].hasEvent = function(obj, idx, meta, stack) {
return ($(obj).data('events') != undefined
&& $(obj).data('events')[meta[3]] != undefined);
};
然后您可以这样使用它:
$(user).not(":hasEvent(save)").on("save", function(){
// Alert the view
});
工作
JQUERY更新>=1.8 从jQuery 1.8开始,events对象发生了一些更改,这使得我的上述代码无法工作,请参见以下摘录: $(element).data(“事件”):在1.6版中,jQuery将其 来自用户数据的内部数据,以防止名称冲突。 然而,有些人使用内部未记录的“事件” 数据结构,所以我们仍然可以通过
.data()
。现在在1.8中删除了它,但是您仍然可以访问
用于调试目的的事件数据,通过$。\u数据(元素,“事件”)
。
请注意,这不是受支持的公共接口;实际数据
结构可能在不同版本之间发生不兼容的更改
因此,我在这里发布了上述示例的更新版本jQuery>=1.8:
检查保存事件是否已绑定,在这种情况下,请不要再次绑定它:
// if no 'save' event already binded
if (!$._data(user, 'events') || !$._data(user, 'events').save) {
// listen for the save event
$(user).on("save", function(){
// Alert the view
});
}
以及自定义jquery伪选择器:
$.expr[':'].hasEvent = function(obj, idx, meta, stack) {
return ($._data(obj, 'events') != undefined
&& $._data(obj, 'events')[meta[3]] != undefined);
};
我同意嵌套侦听器有点奇怪——毕竟,您已经在保存侦听器中了,只是为了按钮单击而不是模型对象 我想我应该重写代码如下:
// if no 'save' event already binded
if (!$(user).data('events') || !$(user).data('events').save) {
// listen for the save event
$(user).on("save", function(){
// Alert the view
});
}
$("#user-devices").on("click", ".device button", function(){
var button = $(this),
deviceId = $(this).closest(".device").attr("data-id"),
device = userDevices.get(deviceId);
if (device.get("Active") === "1")
{
$("#reactivation-warning-dialog").modal("show");
$("#reactivation-warning-dialog .btn-primary").on("click", device.activate);
}
else
{
device.activate();
}
});
//in the device "class"
{
...
...
activate: function() {
//persist and stuf.
//on success...
this.render();
}
render: function() {
button.removeClass("btn-danger").addClass("btn-success");
$("#activation-dialog").modal("show");
}
}
虽然您所建议的是一种更干净的方法,但我的问题是由于save的异步性。因此,听众的依赖性无处不在。不确定数据流回的确切位置,但基本目标似乎是只在一个位置将render()注册为save()回调。因此,也许您可以将其注册到save()方法本身?该模型用于多个视图,但这不是一个坏主意。我可以通过回调实现类似的效果。可能比使用listenersYep更好,传入回调以激活()是我考虑的另一件事。逻辑稍微不那么集中,但它更灵活。我接受尼尔森的答案只是因为它回答了原始问题的“核心”。但是谢谢你的时间Ethan这里有一些非常好的想法,你是否考虑过使用一个预构建的框架,比如knockout.js,将数据和UI绑定在一起。我是一个新的皈依者,我印象深刻@是的,我非常喜欢使用Knockout.js,它看起来很棒。问题是工作不会给我时间去学习它和移植现有的代码。我认为knockout可能会将我编写的代码减半,并解决70%的bug。我可能会在我自己的时间里学习它,并在我有能力的时候提出这个想法。对于任何在jQuery>=1.8中有问题的人,请使用:$。\u data((用户),“events”)嗨,Nelson,你写的那块漂亮的糖在jQuery 1.82中不起作用。我想不出为什么要应用我注意到的更改above@CrimsonChin对于jQuery>=1.8,它应该是
$。\u数据($(用户).get(0),'events')
或只是$。\u数据(用户,'events')
。