光域

<html/>

Backbone源码学习 — Backbone.View

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

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

构造方法

1
2
3
4
5
6
7
8
9
   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)

1
2
3
4
5
6
7
8
9
10
11
12
     setElement: function(element, delegate) {
        if (this.$el) this.undelegateEvents();//如果已经存在this.$el,进行事件解绑

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

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

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

_ensureElement

1
2
3
4
5
6
7
8
9
10
11
12
    _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])

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
       // *{"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中大部分的逻辑都是开发者自己去扩展的。