ホームページ >ウェブフロントエンド >jsチュートリアル >Backbone.jsのModelモデルとViewのソースコードをざっと理解する_基礎知識

Backbone.jsのModelモデルとViewのソースコードをざっと理解する_基礎知識

WBOY
WBOYオリジナル
2016-05-16 15:15:481043ブラウズ

バックボーン.モデル

今日はまず Backbone.js MVC の M について説明します。モデルはバックボーンの中核部分であり、ページ表示コンテンツのデータと、データ操作に関連するさまざまな変換、検証、計算、権限制御が含まれます。 、サーバー側の操作やその他の操作を行うと、Backbone.Model.extend() を通じてモデルを生成できます。もちろん、生成されたモデルを基本クラスとして使用して、さらに多くのモデルを拡張することもできます

 var People = Backbone.Model.extend({
     
 });

 var Man = People.extend({

 });

バックボーン.モデル API

Backbone.Model は、モデルの基本的な操作を実装するための多数のメソッドを提供します。もちろん、最も基本的なのは、Model の属性が変更されると、それに対応する変更が行われるイベント メカニズムです。 attr イベントはトリガーになります。提供される API は次のとおりです:

2016214171632823.png (207×574)

データに対してサーバー側の操作を実行するためのメソッドがあります:

  • sync: xhr
  • の基本クラスである Backbone.sync をラップします。
  • フェッチ: サーバーからデータを取得するために使用されます
  • 保存: データをサーバーに保存します
  • destroy: サーバーからデータを削除します

モデル内のデータ操作のメソッド:

  • get: 属性からデータを取得します
  • set: データを属性に設定します
  • escape: アンダースコアの _.escape
  • を使用してデータをエンコードします
  • has: 属性に対応するデータがあるかどうか
  • 設定解除: 属性からデータを削除します
  • clear: 属性データをクリアします
  • changed: 以前の状態と比較して変更された値
  • (設定、設定解除が実行された)
  • toJSON: 属性をオブジェクトにシリアル化します
  • parse: 設定項目の parse が true の場合、初期化/設定/解除/フェッチなどのデータ操作中にターゲット データが解析され、解析されたオブジェクトが返されます。このメソッドは空のメソッドであるため、オーバーライドする必要があります
  • hasChanged: 以前の状態と比較して変化があったかどうか (設定、設定解除が実行されたかどうか)
  • changeAttributes: 前の状態と比較して発生したすべての値 (設定、設定解除が実行された)
  • previous: 前の状態 (設定、設定解除が実行された)、この属性に対応する値
  • previousAttributes: オブジェクトの前の状態から変更されたすべての値 (設定、設定解除が実行された)
モデル内のデータ検証のメソッド:

    validate: モデル内のデータを検証するために使用されます。デフォルトのメソッド
  • をオーバーライドする必要があります。
  • validationError: 最新の無効が発生したときに返された値を返します
  • isValid: _validate メソッドを呼び出します
いくつかの主要な API について以下で説明します:

コンストラクター

  var Model = Backbone.Model = function(attributes, options) {
     var attrs = attributes || {};
     options || (options = {});
     this.cid = _.uniqueId('c');
     this.attributes = {};
     if (options.collection) this.collection = options.collection;
     if (options.parse) attrs = this.parse(attrs, options) || {};
     attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
     this.set(attrs, options);
     this.changed = {};
     this.initialize.apply(this, arguments);
   };
コンストラクターは主に初期化されたデータとオプションを設定し、次にモデルをマークする一意の CID を生成します。options の parse が true の場合、初期化された値は parse メソッドを介して解析され、すべての初期値が set メソッドを呼び出します。属性に格納され、initialize 初期化メソッドが呼び出されます。モデルの初期化が完了しました。

セット

model.set(attributes, [options])

set メソッドは属性に値を設定します。設定中に client が true に設定されている場合、対応する change:attr イベントがトリガーされます。最後に、set のコードの一部が均一にトリガーされます。メソッドは次のとおりです:

  set: function(key, val, options) {
     //......

      // key值可以是键值对,也可以是一个字符串,将赋值传入attrs属性中  
    if (typeof key === 'object') {
     attrs = key;
     options = val;
    } else {
     (attrs = {})[key] = val;
    }

   // ....

    //对设置的值进行校验 
      if (!this._validate(attrs, options)) return false;
    unset = options.unset; // unset为true时会删除设置的值,unset方法就是通过 set(key,val,{unset:true})去实现的
   
    //当对象正在被被设置的时候,不给 previousAttributes 赋值
    if (!changing) {
     this._previousAttributes = _.clone(this.attributes);
     this.changed = {};
    }
 
    current = this.attributes, prev = this._previousAttributes;
 
    //如果对Id进行了设置,则对对象的id属性也进行改变
    if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
 

    //进行 设置或者是删除操作
    for (attr in attrs) {
     val = attrs[attr];
     if (!_.isEqual(current[attr], val)) changes.push(attr);
     if (!_.isEqual(prev[attr], val)) {
      this.changed[attr] = val;//为model的changed进行设置
     } else {
      delete this.changed[attr];
     }
     unset ? delete current[attr] : current[attr] = val;//如果unset被设置成true了,则进行删除操作
    }
 
    //在silent不为false 的情况下,进行change:attr事件发送
    if (!silent) {
     if (changes.length) this._pending = options;
     for (var i = 0, l = changes.length; i < l; i++) {
      this.trigger('change:' + changes[i], this, current[changes[i]], options);
     }
    }
 

    //触发change事件
    if (changing) return this;
    if (!silent) {
     while (this._pending) {
      options = this._pending;
      this._pending = false;
      this.trigger('change', this, options);
     }
    }
    this._pending = false;
    this._changing = false;
    return this;
   
  }

set のプロセス全体は、受信した値を処理してキーと値のペアに変換し、値を検証し、正確であることを確認してから、設定操作を開始することです。設定する場合、値はチェック時に変更されます。存在する場合は、それを変更されたオブジェクトに追加し、unset の値を確認して、対応する追加、更新、および削除の操作を実行します。次に、change:attr および change イベントが順番にトリガーされます。

保存

model.save([attributes], [options])

save メソッドは、さまざまなデータと構成に応じて作成、更新、またはパッチを使用して、同期イベントをトリガーするために使用されます。以下はコードの一部です:

  save: function(key, val, options) {     
    // ......
 

 
    //当设置了wait属性true的时候 , save方法先不执行set方法(不触发change事件),只执行validate
    if (attrs && !options.wait) {
     if (!this.set(attrs, options)) return false;
    } else {
     if (!this._validate(attrs, options)) return false;
    }

    //如果wait为true,设置this.attributes
    if (attrs && options.wait) {
     this.attributes = _.extend({}, attributes, attrs);
    }
 

    // .....
   
    var model = this;
    var success = options.success;
    options.success = function(resp) {
     // Ensure attributes are restored during synchronous saves.
     model.attributes = attributes;
     var serverAttrs = model.parse(resp, options);
     //如果wait为true , 那么会在请求返回之后才进行set操作
     if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
     if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
      return false;
     }
     if (success) success(model, resp, options);
     //触发 sync 事件
     model.trigger('sync', model, resp, options);
    };

    //生成XHR onerror 回调函数
    wrapError(this, options);
    //选择方法
    method = this.isNew() &#63; 'create' : (options.patch &#63; 'patch' : 'update');
    if (method === 'patch') options.attrs = attrs;
    xhr = this.sync(method, this, options);
 
    // Restore attributes.
    if (attrs && options.wait) this.attributes = attributes;
    //返回xhr对象
    return xhr;
  }

 
save 中最需要注意的就是 wait 的设置,当wait为真的时候,save返回会在xhr返回之后再执行set操作,而不是在xhr之前就进行set操作,因此change事件的触发时机也就不同了。

之前说过整个Backbone都是通过事件串联起来的,所以对于事件触发时机的了解和把握是非常重要的,不然会在开发过程中导致一些奇怪的问题出现。

Backbone.View
前面已经对backbone中的Event、Model、Collection代码进行了分析,现在我们来看下MVC中的V部分,也就是Backbone.View,View在Backbone中主要用于沟通页面中的DOM和Backbone.Model/Collection,页面的逻辑操作,DOM事件的绑定等,View部分的代码非常简答,加上注释只有110左右。 View部分有一下API:

2016214171843674.png (197×245)

方法不多,下面对部分API进行介绍:

构造方法

  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
 var View = Backbone.View = function(options) {
   this.cid = _.uniqueId('view');
   options || (options = {});
   _.extend(this, _.pick(options, viewOptions));
   this._ensureElement();
   this.initialize.apply(this, arguments);
   this.delegateEvents();
 };

构造方法中为View生成了一个唯一的cid,以'view'开头,然后进行对目标属性viewOptions进行合并,接着调用_ensureElement判断el的情况,接着调用delegateEvents进行方法绑定,初始化完成 。

delegateEvents

view.setElement(element)

   setElement: function(element, delegate) {
    if (this.$el) this.undelegateEvents();//如果已经存在this.$el,进行事件解绑

    //对$el进行赋值,本质是一个jquery或者是 Lo-Dash and Zepto 对象
    this.$el = element instanceof Backbone.$ &#63; element : Backbone.$(element);
    //把dom element 赋值给el
    this.el = this.$el[0];

     //如果没有显式传值,则进行事件绑定
    if (delegate !== false) this.delegateEvents();
    return this;
   }

setElement方法用于设置View对应的element , 这个方法在new的时候会被调用, 如果想要在使用过程中改变View的dom元素指向,可调用这个方法进行重新设置

_ensureElement

  _ensureElement: function() {
     //如果已经对el进行设置,直接调用setElement方法
    if (!this.el) {//如果没有设置,生成一个元素对象,再调用setElement方法
     var attrs = _.extend({}, _.result(this, 'attributes'));
     if (this.id) attrs.id = _.result(this, 'id');
     if (this.className) attrs['class'] = _.result(this, 'className');
     var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
     this.setElement($el, false);
    } else {
     this.setElement(_.result(this, 'el'), false);
    }
  }

_ensureElement这个方法是内部方法,在构造函数中使用,用于判断指定的el在页面中存不存在,如果存在则对$el进行赋值,如果不存在,则生成一个$el,但是要注意这个对象是没有落地到dom树中的 。

delegateEvents

delegateEvents([events])

    // *{"event selector": "callback"}*
   //
   //   {
   //    'mousedown .title': 'edit',
   //    'click .button':   'save',
   //    'click .open':    function(e) { ... }
   //   }

   delegateEvents: function(events) {
      //如果不存在events,则直接返回
      if (!(events || (events = _.result(this, 'events')))) return this;
   
      //先解除所有的事件绑定
      this.undelegateEvents();
   
      //处理每个事件
      for (var key in events) {
       var method = events[key];
       //解析回调函数
       if (!_.isFunction(method)) method = this[events[key]];
       if (!method) continue;
   
       //对选择器进行分析
       var match = key.match(delegateEventSplitter);
       var eventName = match[1], selector = match[2];
       method = _.bind(method, this);
   
       //绑定的事件名都是以 eventName + '.delegateEvents' + cid 组成,
       //这么做能够在undelegateEvents的时候选择到这个View的所有事件
       eventName += '.delegateEvents' + this.cid;
       if (selector === '') {
        this.$el.on(eventName, method);
       } else {
        this.$el.on(eventName, selector, method);
       }
      }
      return this;
   }

在View中你可以使用一个 key:value 集合指定对应的事件,在初始化的时候构造函数会调用delegateEvents进行绑定,需要注意的是所有在key中指定的元素的父元素都必须是$el,也就是说元素必须是$el的子节点,否则绑定失败。

View和其他backbone模块一个区别就是没有自己的内建自定义事件,当然他也组合了Events模块,但是所有的事件都需要自己进行建立。View主要是一个MVC模型的承载,其实真正的功能不多,其实从模型层面上看V在前端开发中是最接近业务逻辑的,所以在View中大部分的逻辑都是开发者自己去扩展的。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。