骨干模型对象....它们存储在哪里,以便DOM可以与它们交互?

时间:2015-04-02 22:49:20

标签: javascript jquery backbone.js backbone-views backbone-events

我刚才意识到我不知道在骨​​干方面我到底做了什么。当我试图找出一个有效的策略去除模型上的视图事件监听器时,我开始意识到这一点。然后我问"嗯,现在视图已经呈现给DOM了,模型在哪里?"然后我问"我在函数体内创建的这个模型对象是怎样的,因此我已经将视图呈现给DOM,保持状态?#34; AHHHHHHHH !!!!!!!!!

实施例。

查看构造函数

Timeclock.Views.JobNewView = Backbone.View.extend({
  template: JST['jobs/_form'],
  events:{
   'blur #job_form :input':'assignValue'
  },
  initialize: function(options){
    this.listenTo(this.model, 'failed-request', this.failedLocationRequest);
    this.listenTo(this.model, 'updated-location', this.updatedLocation);
    this.listenTo(this.model, 'sync', this.renderJobView); 
    this.listenTo(this.model, 'invalid', this.displayModelErrors);
    this.listenTo($(window), 'hashchange', this.clearListeners);
  },
  render: function(){
    this.$el.html(this.template({attributes: this.model.attributes}));
    this.$el.find('#address_fields').listenForAutoFill();
    return this;
  },
  assignValue: function(e){
    var $field = $(e.currentTarget)
    var attr_name = $field.attr('name');
    var value = $field.val();
    this.model.set(attr_name, value);
  }...
});

DOM的功能渲染视图

renderCollaboratingView: function(e){
  var job = this.model;
  var $row = $(e.currentTarget);
  job.set({customer_id: $row.data('id')});
  var model_view = new this.ViewConstructor({model: job});
  $container.html(model_view.render().el);
}

那么我传递给视图对象的模型是如何持久化的,以便DOM交互可以在底层模型对象上设置属性值?

我理解骨干视图只是声明性地编写DOM侦听器的包装器,但是DOM事件如何作用于上面示例中的底层模型对象?一旦renderCollaboratingView()函数退出,我传递给视图的模型如何仍然与之交互?

我可以想到两种方式:

1)模型对象通过jquery对象绑定到DOM。我在视图中声明的所有事件侦听器都知道底层模型对象在jquery对象上的位置('模型'属性?)。

2)Backbone正在创建一些对象命名空间,视图知道它存储支持DOM的模型和集合的位置。我感觉它是#1,但谁知道。

我再次来到这里是因为我试图理解为什么我需要删除我首先进入视图的模型上的监听器。如果主干视图实际上只是jquery对象,那么当从DOM中删除支持jquery对象的元素时,是不是从DOM元素中删除了jquery侦听器?如果我不打算完全破坏视图并保存以供以后使用,我是否只需要删除监听器?

任何可以提供的帮助都会得到很大的帮助。存在危机。

由于

2 个答案:

答案 0 :(得分:2)

  

那么我传递给视图对象的模型是如何持久化的,以便DOM交互可以在底层模型对象上设置属性值?

Backbone模型和视图只是在页面范围内存在于内存中的Javascript对象(与任何其他Javascript一样)。如果你要做...

var name = 'Peter';
var person = new Backbone.Model({ name: 'Peter' });
var view = new Backbone.View({ model: person } );

...然后namepersonview都只是内存中的对象。它们与jQuery没有关系;它们与DOM无关。如果你实现render(),View恰好能够创建DOM元素,但即使这样,这些元素也不必永远地附加到页面的实时DOM上。

  

......在上面的例子中,DOM事件如何作用于底层模型对象?一旦renderCollaboratingView()函数退出,我传递给视图的模型如何仍然与之交互?

根据您显示的代码,模型不会直接与之交互。你的events哈希......

events:{
    'blur #job_form :input':'assignValue'
},

...确实说blur元素中发生job_form事件的任何时候,它都会在名为assignValue的视图上调用方法。该方法可能与模型交互(它可能会,但对吗?),但DOM事件根本不会直接导致与模型的交互。

  

如果主干视图实际上只是jquery对象,那么当从DOM中删除支持jquery对象的元素时,是不是从DOM元素中删除了jquery侦听器?

Backbone的监听器与jQuery监听器完全不同。他们倾听以Backbone为中心的事件。 See here获取Backbone组件触发的内置事件列表。 View的事件哈希是一个很好的约定,用于侦听DOM事件;它基本上是a nice wrapper围绕jQuery事件委托的概念。

  

如果我不打算完全破坏视图并将其保存以供以后使用,我是否只需要删除侦听器?

如果不删除侦听器,则无论侦听组件是否正在更改页面,它们都会在相关事件发生时继续运行。假设你有一个Backbone.View做了类似的事情:

var MyView = Backbone.View.extend({
    // ...
    events: {
        // Don't do this!
        'click': '_onClick'
    },
    // ...

    _onClick: function() {
         this.$el.append('Clicked!');
    }
 });

任何时候在页面上发生任何click DOM事件,此视图会将文本Clicked!附加到其内部DOM元素。当视图附加到页面的DOM时,每次点击都会显示Clicked!。当从DOM中删除视图时,该函数将在每次单击时仍然运行...但由于View的内部根元素未附加到任何函数将无效。

这是一种内存泄漏,因为垃圾收集器会清除MyView的任何实例。但是特别邪恶的副作用是使用CPU时间做一些完全没用的事情。现在想象一下,如果事件监听器做了什么后果。页面的性能将受到影响。

答案 1 :(得分:1)

JavaScript有垃圾收集。对象不会被破坏然后它们超出范围。当一个对象X看到没有人有X的引用(或指向)时,它会被运行时系统收集。

Backbone View也是一个对象。对象可以存储对另一个对象的引用。

renderCollaboratingView中,您写道:

  var model_view = new this.ViewConstructor({model: job});

model_view是您视图的对象。你通过了job这是你的模特:

 renderCollaboratingView: function(e){
    var job = this.model; 
    ....
 }

您可以在骨干注释代码中查看此行:BackBone View Options。 (我建议您在阅读答案后查看链接)

该行是:

var viewOptions = ['model', 'collection', 'el', 'id', 
                   'attributes', 'className', 'tagName', 'events'];

然后Backbone View定义为:BackBone View

是:

 var View = Backbone.View = function(options) {
    this.cid = _.uniqueId('view');
    options || (options = {});
    _.extend(this, _.pick(options, viewOptions));
    this._ensureElement();
    this.initialize.apply(this, arguments);
  };

看看行:

 _.extend(this, _.pick(options, viewOptions));

和你的代码:

 var model_view = new this.ViewConstructor({model: job});
  

那么我传递给视图对象的模型是如何持久化的,以便DOM交互可以在底层模型对象上设置属性值?

如果合并点:您正在将model传递给您的视图。您还可以在'collection', 'el', 'id', ...中传递viewOptions之类的其他内容。

他们从您在视图对象中传递的对象pick{model: job}获得extended

这是您的视图对象引用它所给出的模型的方式。

  

我再次来到这里是因为我试图理解为什么我需要删除我首先进入视图的模型上的监听器。

正如我所说,只是从DOM中移除view-object不会destroy它。您必须删除其他对象(此处为view-object)所具有的model的所有引用。

当你说:

initialize: function(options){
     this.listenTo(this.model, 'failed-request', this.failedLocationRequest);
     ....
在你看来

。您告诉model在模型的事件failedLocationRequest上调用您的视图对象的failed-request。只有当您的model's object存储对view's object的引用时,才可以执行此操作。所以,你的观点不会被破坏。

不在dom中的视图对象将继续从模型和他们注册的所有其他地方(除了dom)接收此类事件,并且会在后台执行您从未想过的事情。绝对不是你想要的......

简单的建议,在您的观点上调用removeBackBone View remove

并阅读stopListening

相关问题