设想以下简单模型和 View :
app.Messages = Backbone.Model.extend({
defaults: function() {
return {
message: "an empty message…",
messageActive: false
};
}
});
app.MessageView = Backbone.View.extend({
tagName: "li",
template: _.template($("#template").html()),
events: {
"click": "open"
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
this.listenTo(this.model, "message:hide", this.hide);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
open: function() {},
hide: function() {
this.model.set("messageActive", false);
this.$el.removeClass("show-message");
}
});
模型是集合的一部分,所有内容都由父 View 组合在一起(针对此问题进行了简化):
app.AppView = Backbone.View.extend({
el: "#messages",
initialize: function() {
this.listenTo(app.messages, "message:show", this.foo);
},
foo: function(model) {
var open = app.messages.where({messageActive: true});
open.forEach(function(e, i) {
if (model != e) {
e.trigger("message:hide");
}
});
},
在任何给定时间只能激活该集合中的一条消息。这意味着只要单击关闭的消息,任何打开的消息都将被关闭。现在的问题涉及 app.MessageView.open()
的功能。恕我直言,它可以使用 jQuery.siblings()
来隐藏所有 sibling 的消息并显示自己的消息:
open: function() {
this.$el
.addClass("show-message")
.siblings(".show-message")
.removeClass("show-message");
}
我个人认为这个解决方案非常优雅,我只是不喜欢它需要知道它有 sibling 。我的其他实现将使用一个自定义事件,该事件被父 View (app.AppView.foo()
) 拦截,然后在每个事件上调用 app.MessageView.close()
打开消息:
open: function() {
this.model.set("messageActive", true).trigger("message:show", this.model);
this.$el.addClass("show-message");
}
这对我来说感觉有点“ Backbone ”,但似乎有点过度设计。 ;-)
我可以想到第三种可能性,其中父 View 简单地跟踪最后打开的模型本身并触发任何被模型 View 拦截的关闭事件(似乎易于管理但对我来说不是很 Backbone ;-) ).我已经在此处介绍了很多关于 SO 的博客文章和问题,但没有得出真正令人满意的结论。也许有人可以阐明这个具体问题。
最佳答案
编辑:完全错过了消息 View 上的点击事件,因此修改了我的答案。
您可以在点击 View 时触发模型上的点击事件,然后等待父 View 触发模型上的显示和隐藏事件。
app.MessageView = Backbone.View.extend({
tagName: "li",
template: _.template($("#template").html()),
events: {
"click": "isClicked"
},
initialize: function() {
this.listenTo(this.model, "change", this.render);
this.listenTo(this.model, "message:show", this.open);
this.listenTo(this.model, "message:hide", this.hide);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
isClicked: function(){
this.model.trigger("message:clicked");
},
open: function() {
this.model.set("messageActive", true);
this.$el.addClass("show-message");
},
hide: function() {
this.model.set("messageActive", false);
this.$el.removeClass("show-message");
}
});
您的父 View 现在负责在点击其中一个 subview 时向模型发送正确的事件。
app.AppView = Backbone.View.extend({
el: "#messages",
initialize: function() {
this.listenTo(app.messages, "message:clicked", this.foo);
},
foo: function(model) {
var open = app.messages.where({messageActive: true});
open.forEach(function(e, i) {
if (model != e) {
e.trigger("message:hide");
}
});
// Because we retrieved the currently active models before sending this event,
// there will be no racing condition:
model.trigger("message:show");
},
也许这不是实现这种事情的最短途径。但它完全是事件驱动和可定制的。
关于javascript - 使用 Backbone 事件来切换 Collection View 属性或 jQuery.siblings()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20920953/