如何将Backbone.View绑定到DOM中类似元素列表中的“单个”DOM元素

我有以下页面结构:

    • Label 1
    • Label 2
  • ...
  • ...
  • ...
  • ...

这是过于简单化的视图:

  var MyView = Backbone.View.extend({ el:$('.listOfPosts'), initialize: function() { _.bindAll(this,"postClicked"); }, events: { "click .wcCheckbox":"postClicked" }, postClicked: function() { alert("Got aa click in the backbone!"); } }); 

问题:我想知道被点击的post的数据ID。 使用简单的JQuery,我可以执行以下操作:

 $('.wcCheckbox').live('click' function() { alert("Data id of post = "+$(this).parents('.WCPost').data('data-postId')); } 

现在我知道Backbone会执行事件委托,所以它需要el属性中的DOM引用。 如果我给它.listOfPosts然后事件似乎完全开火但是要检查“哪个”post我将不得不继续遍历DOM并挑选出被选中的元素! 在我看来这将是相当昂贵的! 我如何在Backbone中为每个post做这个? 即,如何将视图绑定到每个单独的li.WCPost ??

注意:我不是使用普通的vanilla jQuery,因为我需要编写的代码最好用Backbone的模块化设计完成,但是因为我不是Backbone的专业人员(但是),有点困惑……

据我所知,在postClicked()函数中使用类似$(event.target).data('postId')的东西是执行此类操作的postClicked()方法。

事件的广泛使用起初可能看起来很不寻常,但如果使用得当,它是改善代码组织的好方法。 在大多数情况下,你真的可以从事件中获得所需的所有数据,特别是如果你有jQuery。 (请注意,传递给postClicked函数的事件是一个常规的jQuery事件对象, 您可以找到有关它的所有内容 postClicked 使用 jQuery的delegate()函数来绑定事件。)

* * *

但是,您仍然可以在视图的initialize()方法中自行绑定事件。

 initialize: function() { // Custom binding code: this.$('.wcCheckbox').live('click' function() { alert("Data id of post = "+$(this).parents('.WCPost').data('data-postId')); } // No need for this anymore: // _.bindAll(this,"postClicked"); }, 

this.$()是一个自动将jQuery选择器作用于视图的函数,相当于$(, this.el) 。)

* * *

另一个解决方案(最终可能是最自然的,但最初需要一些工作)是创建一个PostView类,并将其用于单个post和绑定复选框点击事件。

要显示post,请在post列表视图中浏览Posts集合,为每个Post实例创建一个视图,然后将其附加到.listOfPosts元素。

您不再需要解决访问postID的问题,因为您将在PostView上绑定复选框点击事件。 因此,在处理程序中,函数可以轻松地通过相关模型( this.model.get('id') )或通过视图元素( $(this.el).data('postId') )查找post的ID 。

* * * 更新

既然我独立于Backbone创建了post的DOM,我如何像我在问题中提到的那样“改进”每个post的视图?

我不想重构大量客户端代码只是为了容纳Backbone。 但是如何将视图绑定到每个li?

如果您决定使用MVC和面向对象的JavaScript,则不应直接管理post的DOM元素:您创建PostView实例,然后它们创建相应的元素,如todos.js,并填充它们呈现的模板。 (如果您不想自动创建元素,Backbone允许您通过在子类化时指定el属性来手动将新创建的视图绑定到元素。这样,您可以将视图绑定到现有元素,例如,在初始化页面加载。)任何与特定post相关的DOM修改都应该在PostView类中进行。

OOP方法优于基于DOM的一些优点:

  • 视图比DOM元素更适合数据存储。

    请注意,使用您当前的方法,您将广泛使用data属性 – 例如,存储post的ID。 但是如果您正在操作视图,则不需要这样做:每个PostView已经知道其相关模型,因此您可以通过例如view.model.get('postId')轻松获取post id,如以及您想要的任何其他发布数据。

    您还可以存储不属于Post模型的视图特定数据 :例如,动画和/或显示状态(展开,选定,…)。

  • 视图更适合定义元素的行为。

    例如,如果要为每个post指定一个复选框单击事件处理程序,则将此代码放入PostView类中。 这样, 事件处理程序就可以了解所有发布数据 ,因为视图可以访问它。 此外, 代码更好的结构 – 什么处理特定的post,属于PostView ,并没有妨碍你。

    另一个例子是在视图上定义render()函数的约定。 模板函数或模板字符串存储在视图属性templaterender()呈现该模板并使用生成的HTML填充视图的元素:

     render: function() { $(this.el).html(this.template({ modelData: this.model.toJSON() })); }, 
  • 操纵DOM可能比操纵对象慢。

但是 ,基于DOM的方法(看起来像你现在使用的那样)有其自己的优点,特别是对于不那么复杂的应用程序。 另请参阅: 面向对象的Javascript与纯jQuery和.data存储

有没有办法将视图绑定到非骨干生成的当前和未来DOM元素?

这是否意味着骨干需要从一开始就使用,并且难以“改造”这么说?

如上所示,您不需要将视图绑定到将来的 DOM元素(使用视图来操作它们)。

关于绑定到初始化时已经在页面上的DOM元素,我不知道“正确”的方法。 我目前的方法是清除现有元素并从头开始创建视图,这将自动创建相应的DOM元素。

这意味着浏览器在页面初始化时还需要做一些额外的工作。 对我来说,OOP的优势certificate了这一点。 从用户的角度来看,它也很好,我想:在初始初始化之后,一切都会更快,因为在用户执行注销之前不需要重新加载页面。

(顺便说一下,我认为我应该澄清使用MVC方法的重点,至少对我而言:创建一个客户端应用程序,基本上,使用后端服务器提供的API,本身最能完成工作。为模型提供JSON数据,你的客户端应用程序完成剩下的工作,广泛使用AJAX。如果你在用户与你的站点交互时进行正常的页面加载,那么这样的MVC和沉重的客户端可能是你的开销。是你必须重构一些代码,根据你的要求和资源,这可能不是一个选项。)

请注意,在我看来,事件会传递对自己及其原点的引用,这是访问事件起源的最简单方法。

试试这样,看看这是否是你需要的(而且不那么复杂):

 var MyView = Backbone.View.extend({ el:$('.listOfPosts'), initialize: function() { _.bindAll(this,"postClicked"); }, events: { "click .wcCheckbox":"postClicked" }, postClicked: function(e) { alert("Here is my event origin: "+e.target); } }); 

可以从事件中获得大量数据,如下所示: http : //www.quirksmode.org/js/events_properties.html

一旦你了解javascript事件,你可能会查看PubSub / Observer模式以获得更多解耦的UI组件,这里有一个很好的介绍:

http://blog.bobcravens.com/2011/01/loosely-coupled-javascript-using-pubsub/

没有什么能阻止你嵌套视图。 也就是说,外部视图表示UL。 UL视图将呈现一堆内部LI视图。 您可以尽可能深入地嵌套视图。

我一直在以这种方式做得非常成功。