首页 > 教育学习 > 为什么 > 如何解决 Backbone 的相同 Model 事件绑定问题?

如何解决 Backbone 的相同 Model 事件绑定问题?
2012-01-19 20:25:02   来源:   点击:

    如何解决 Backbone 的相同 Model 事件绑定问题?假如页面有两个 View(viewA, viewB),每个 View 有自己的 Collection,那么如果两个 collection 中元素有重复,会出现两个数据相同但不是同一对象的 model:viewA.collection.fetch();viewB.collection.fetch();var id = 1;var modelA = viewA.collection.get(id);var modelB = viewB.collection.get(id);此时 modelA 和 modelB 应该有相同的数据,但二者是不同的对象。问题在于,如果 viewA 绑定了 modelA 的 change 事件,那么修改 modelB 的属性时,A 是不会知道的。那么,如何让 modelB 发生改变时,modelA 也会将自己的属性同步成跟 modelB 一样,并且通知 viewA 呢? 补充下要求,解决方案应该在设计上优美,可复用,不修改 Backbone 源码

    2 个答案

    • 答案 1:

      我在你的应用场景下做了点测试,在没有修改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"}); 应用的后端我采用的CakePHP做的,如果需要的话,我可以将整个应用的代码和数据库结构打包发给你
    • 答案 2:

      你可以把change事件绑定在collection上[1]。 [1]: documentcloud.github.com/backbone...

相关热词搜索:

上一篇:国内有http://buysellads.com/这样的平台吗?
下一篇:北京到上海做什么车?