如何解决 Backbone 的相同 Model 事件绑定问题

 我来答
信玄居士72a5251
2015-08-24 · TA获得超过4406个赞
知道大有可为答主
回答量:3257
采纳率:100%
帮助的人:1805万
展开全部

我在你的应用场景下做了点测试,在没有修改BackBone任何源代码的情况下实现了你的需求,下面是具体的解决方案: 
按照你的需要定义Model,Collection,ItemView,AppView,其中ItemView具体是你需要更新的原子视图,而AppView是应用程序视图; 
ItemViewA和ItemViewB应该分布在两个不同的AppView实例中,要做到这点也很容易,因为从业务逻辑上来讲,相同的数据分布在不同的地方可以看成是不同的应用域,上面几个的关系是: 
Collection拥有多个Model,Model定义了数据的操作,每个ItemView对应1个Model,而1个AppView对应1个Collection,因为在javascript中的对象是按引用传递的,两个AppView的实例所引用的Collection实际指向相同的对象,这样当AppViewA中的某个ItemViewA触发某种事件,肯定会自动的触发最底层的同1个Model的事件。 

这样说来可能有点抽象,我根据官方示例的Todos应用改了改,下面是相关的代码,重点需要注意的部分用黑体字标出,你很快就明白了。 

主要的客户端JS代码: 

// Todo Model 

// Our basic **Todo** model has ` id`, `content`, `done` attributes. 
var Todo = Backbone.Model.extend({ 

// If you don't provide a todo, one will be provided for you. 
EMPTY: "empty todo...", 

// Ensure that each todo created has `content`. 
initialize: function () { 
if (!this.get("content")) { 
this.set({"content": this.EMPTY}); 

}, 

// Toggle the `done` state of this todo item. 
toggle: function () { 
this.save({done: Math.abs(1 - parseInt(this.get("done"))) }); 
this.change(); 
}, 

// Remove this Todo from *database* and delete its view. 
clear: function () { 
this.destroy(); 
this.view.remove(); 


}); 

// Todo Collection 

// The collection of todos is backed by *database* instead of a remote 
// server. 
var TodoList = Backbone.Collection.extend({ 

// Reference to this collection's model. 
model: Todo, 

// Save all of the todo items under the `"todos"` namespace. 
//localStorage: new Store("todos"), 
url: '/todos', 

// Filter down the list of all todo items that are finished. 
done: function () { 
return this.filter(function (todo) { 
return parseInt(todo.get('done')); 
}); 
}, 

// Filter down the list to only todo items that are still not finished. 
remaining: function () { 
return this.without.apply(this, this.done()); 
}, 

// Todos are sorted by their original insertion order. 
comparator: function (todo) { 
return parseInt(todo.get('id')); 


}); 

// Create our global collection of **Todos**. 
var Todos = new TodoList(); 

// Todo Item View 

// The DOM element for a todo item... 
var TodoView = Backbone.View.extend({ 

//... is a list tag. 
tagName: "li", 

// Cache the template function for a single item. 
template: _.template($('#item-template').html()), 

// The DOM events specific to an item. 
events: { 
"click .check" : "toggleDone", 
"dblclick div.content" : "edit", 
"click span.destroy" : "clear", 
"keypress .input" : "updateOnEnter" 
}, 

// The TodoView listens for changes to its model, re-rendering. 
// Since there's a one-to-one correspondence between a **Todo** 
// and a **TodoView** in this app, we set a direct reference 
// on the model for convenience. 
initialize: function () { 
_.bindAll(this, 'render', 'close'); 
this.model.bind('change', this.render); 
this.model.view = this; 
}, 

// Re-render the contents of the todo item. 
render: function () { 
$(this.el).html(this.template(this.model.toJSON())); 
this.setContent(); 
return this; 
}, 

// To avoid XSS (not that it would be harmful in this particular app), 
// we use `jQuery.text` to set the contents of the todo item. 
setContent: function () { 
this.$('.content').text(this.model.get('content')) 
.autotag(this.model.get('tags'), {url: '#/tag/'}) 
.autolink({text: '(点此)'}); 
this.$('.created').attr({'title': this.model.get('created')}).prettyDate(); 
this.input = this.$('.input'); 
this.input.bind('blur', this.close); 
this.input.val(this.model.get('content')); 
}, 

// Toggle the `"done"` state of the model. 
toggleDone: function () { 
this.model.toggle(); 
}, 

// Switch this view into `"editing"` mode, displaying the input field. 
edit: function () { 
$(this.el).addClass("editing"); 
this.input.focus(); 
}, 

// Close the `"editing"` mode, saving changes to the todo. 
close: function () { 
this.model.save({content: this.input.val()}); 
$(this.el).removeClass("editing"); 
}, 

// If you hit `enter`, we're through editing the item. 
updateOnEnter: function (e) { 
if (e.keyCode === 13) { 
this.close(); 

}, 

// Remove this view from the DOM. 
remove: function () { 
$(this.el).fadeOut('fast', function () { 
$(this).remove(); 
}); 
}, 

// Remove the item, destroy the model. 
clear: function () { 
this.model.clear(); 


}); 

// The Application 

// Our overall **AppView** is the top-level piece of UI. 
var AppView = Backbone.View.extend({ 

// Instead of generating a new element, bind to the existing skeleton of 
// the App already present in the HTML. 
el: $("#todoapp"), 

// Our template for the line of statistics at the bottom of the app. 
statsTemplate: _.template($('#stats-template').html()), 

// Delegated events for creating new items, and clearing completed ones. 
events: { 
"keypress .new-todo": "createOnEnter", 
"keyup .new-todo": "showTooltip", 
"click .clear a": "clearCompleted" 
}, 

// At initialization we bind to the relevant events on the `Todos` 
// collection, when items are added or changed. Kick things off by 
// loading any preexisting todos that might be saved in *database*. 
initialize: function (options) { 
_.bindAll(this, 'addOne', 'addAll', 'render'); 

this.input = this.$(".new-todo"); 
// 这里需要重新定义AppView的el属性,因为是两个不同的应用

this.el = $(options.element); 

Todos.bind('add', this.addOne); 
Todos.bind('refresh', this.addAll); 
Todos.bind('all', this.render); 

Todos.fetch(); 
}, 

// Re-rendering the App just means refreshing the statistics -- the rest 
// of the app doesn't change. 
render: function () { 
var done = Todos.done().length; 
this.$('div.stats').html(this.statsTemplate({ 
total: Todos.length, 
done: Todos.done().length, 
remaining: Todos.remaining().length 
})); 
}, 

// Add a single todo item to the list by creating a view for it, and 
// appending its element to the `<ul>`. 
addOne: function (todo) { 
var view = new TodoView({model: todo}); 
this.$("ul.todos").prepend(view.render().el); 
this.$("ul.todos li:first").fadeIn('fast'); 
}, 

// Add all items in the **Todos** collection at once. 
addAll: function () { 
this.$("ul.todos").html(''); 
Todos.each(this.addOne); 
}, 

// Generate the attributes for a new Todo item. 
newAttributes: function () { 
return { content: this.input.val() }; 
}, 

// If you hit return in the main input field, create new **Todo** model, 
// persisting it to *database*. 
createOnEnter: function (e) { 
if (e.keyCode !== 13) { 
return; 

Todos.create(this.newAttributes()); 
this.input.val(''); 
}, 

// Clear all done todo items, destroying their models. 
clearCompleted: function () { 
_.each(Todos.done(), function (todo) { todo.clear(); }); 
return false; 
}, 

// Lazily show the tooltip that tells you to press `enter` to save 
// a new todo item, after one second. 
showTooltip: function (e) { 
var tooltip = this.$(".ui-tooltip-top"); 
var val = this.input.val(); 
tooltip.fadeOut(); 
if (this.tooltipTimeout) { 
clearTimeout(this.tooltipTimeout); 

if (val === '' || val === this.input.attr('placeholder')) { 
return false; 

var show = function () { tooltip.show().fadeIn(); }; 
this.tooltipTimeout = _.delay(show, 1000); 


}); 

// 在两个不同的地方创建两个AppView实例,其中1个App更新之后,另外1个也会随着更新 
var App = new AppView({element: '#todoapp'}); 
var App2 = new AppView({element: '#todoapp2'});
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式