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

Backbone model objects.... where are they stored so that the DOM can interact with them?

我刚刚意识到,当涉及到 backbone 时,我不知道我到底在做什么。当我试图找出一个有说服力的策略来移除模型上视图的事件监听器时,我意识到了这一点。然后我问 "well, where is the model anyways now that the view has been rendered to the DOM?" 然后我问 "how is this model object that I created inside a function body, and is therefore out of scope now that I have rendered the view to the DOM, maintaining state?" 啊啊啊啊啊啊!!!!!!!!!

例如。

查看构造器

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 交互可以在基础模型对象上设置属性值?

我知道 backbone 视图只是一个包装器,用于以声明方式编写 DOM 侦听器,但是 DOM 事件如何作用于上面示例中的基础模型对象?一旦 renderCollaboratingView() 函数退出,我传递给视图的模型如何仍在与之交互?

我可以想到两个办法:

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

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

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

如能提供帮助,我们将不胜感激。存在生存危机。

谢谢

So how is the model that I am passing to the view object persisted so that the DOM interactions can set attribute values on the underlying model object?

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

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

... 那么 namepersonview 都只是内存中的对象。它们与 jQuery 无关;它们与 DOM 无关。如果您实现 render(),视图恰好能够创建 DOM 元素,但即便如此,这些元素也根本不必附加到页面的实时 DOM。

... how are DOM events acting on the underlying model object in the example above? As soon as the renderCollaboratingView() function has exited how is the model that I passed to the view still being interacted with?

根据您显示的代码,模型没有直接交互。你的 events 散列 ...

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

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

If backbone views are really just jquery objects then aren't jquery listeners removed from DOM elements when the element backing the jquery object is removed from the DOM?

Backbone 的听众与 jQuery 的听众完全不同。他们监听以 Backbone 为中心的事件。 See here for the list of built-in events that Backbone components fire. A View's events hash is a nice convention that is used to listen for DOM events; it's basically a nice wrapper 围绕事件委托的 jQuery 概念。

Do I only need to remove the listeners if I am going to not destroy the view entirely and save it for later use?

如果您不删除侦听器,只要相关事件发生,它们将继续 运行,无论侦听组件是否正在更改页面。假设你有一个 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 中删除时,该函数将在每次单击时 仍然 运行...但是由于视图的内部根元素未附加到该函数将无效的任何内容。

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

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 注释代码中查看这一行:BackBone View Options。 (我建议您在阅读答案后查看 link)

该行是:

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

然后 Backbone 视图定义为: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});

So how is the model that I am passing to the view object persisted so that the DOM interactions can set attribute values on the underlying model object?

如果合并点:您正在将 model 传递到您的视图。您还可以在 viewOptions.

中传递其他类似 'collection', 'el', 'id', ... 的内容

它们从您传递的对象 {model: job} 和视图对象中的 extended 得到 pick

这就是您的视图对象如何引用给定的模型。

Once again, I got here because I was trying to understand why I need to remove the listeners on the model that I passed into view in the first place.

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

当你说:

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

在你看来。您告诉 model 在模型的事件 failed-request 上调用视图对象的 failedLocationRequest。这只有在您的 model's object 存储对 view's object 的引用时才有可能。所以,你的观点没有被破坏。

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

简单的建议,请致电removeBackBone View remove

并阅读stopListening