zoukankan      html  css  js  c++  java
  • Backbone源码解析(四):View(视图)模块

    View视图故名思义,它控制的是界面。我们可以把一个大的网页分成很多部分的视图,按照backbone的架构,每一个视图对应都是一个对象,我们可以通过元素的钩子(id或者class或者其他选择器)把它们封装到View对象中集中操作。由于传统项目中界面视图和数据不分层,使得各种操作数据逻辑和视图逻辑的代码混杂在一起,提高了代码的耦合度。backbone就是将这种情况作了很好的处理。下面我们通过一个简单的例子一步步地讲明白它的具体设计思路:

    首先我们编写基础的html:

    <div id="m" style="height:200px; 200px; background:red;">
    	<div class="c" style="height:100px; 100px; background:green;"></div>
    </div>
    

    两个div,父元素的id为m,子元素的class为c。我们要做的是利用bk框架,将model里面一段数据(‘hello’)放到子元素的innerHTML里面,通过点击事件弹出它的内容。下面我们看下js代码:

    //M扩展了一个模型,给定一个初始值
    var M = Backbone.Model.extend({
    	defaults : {
    		text : 'hello world'
    	}
    });
    //实例化一个模型
    var m = new M();
    //继承并且扩展一个View
    var V = Backbone.View.extend({
    	//初始化函数
    	initialize : function() {
    		this.render();
    	},
    	//渲染模版,在这里我们为了简化使用的事直接给html赋值的方法
    	render : function() {
    		var t = this.model.toJSON().text;
    		$(this.el).find('.c').html(t);
    	},
    	//添加内部事件
    	events : {
    		'click .c' : 'click'
    	},
    	//内部时间具体的实现方法
    	click : function(e) {
    		var text = $(e.target).html();
    		alert(text);
    	}
    });
    //创建View的实例,并且给定基础值。
    var v = new V({model : m, el : '#m'})
    

    在上面我们新建了一个模型,给它赋默认的一个值,我们还建立了一个视图,并且指向了节面的元素。通过对html源码的查询,我们可以看到,子元素已经填充了model中的hello world 数据:

    并且绑定了click事件:

    那么它是怎么样实现的呢?首先,我们从实例化V这个对象说起,下面是关于View的构造函数的源码:

    e.View = function(a) {
    	this.cid = f.uniqueId("view");
    	this._configure(a || {});
    	this._ensureElement();
    	this.delegateEvents();
    	this.initialize.apply(this, arguments)
    };
    var u = /^(S+)s*(.*)$/,
    n = ["model", "collection", "el", "id", "attributes", "className", "tagName"];
    

    View的构造函数主要做了几件事情,也就是说在实例化View的时候它1、首先配置默认的值的参数->_configure():

    _configure: function(a) {
    	this.options && (a = f.extend({}, this.options, a));
    	for (var b = 0, c = n.length; b < c; b++) {
    		var d = n[b];
    		a[d] && (this[d] = a[d])
    	}
    	this.options = a
    },
    

    此方法是对实例化的时候对内部本身的一些值重新赋值。可以看到,里面循环了一个变量n,n指的就是一个包含可以重新定义值的数组,我们可以在之前关于n的定义中找到n所包含的一些值 ["model", "collection", "el", "id", "attributes", "className", "tagName"];如果你在实例化的时候传入的字面量中有n数组中包含的值的健名,那么它就会赋值到view这个对象里面通过this.xxxx或者this.options.xxxx调用到,而其他不在n数组中的属性则不会起任何作用。

    第二步确认传入了el,也就是是说确保这个view对象有关联的html元素存在->_ensureElement():

    _ensureElement: function() {
    	if (this.el) {
    		if (f.isString(this.el)) this.el = g(this.el).get(0)
    	} else {
    		var a = this.attributes || {};
    		if (this.id) a.id = this.id;
    		if (this.className) a["class"] = this.className;
    		this.el = this.make(this.tagName, a)
    	}
    }
    

    我们可以从里面看到,这个方法会判断我们在实例化时是有el这个属性是否存在,如果没有它会根据其他的属性配置自动创建一个元素出来,这里用的是自己的方法make()来制造对象的html元素。这里也许大家或有疑问,那就是我不知道需要创建那种类型的元素。bk默认创建的是div元素,因为它默认的就是这样的,在源码中我们可以看到this.tagName属性被赋予了默认的值,所有make出来的时div,当然前提是如果你没有覆盖它的话。

    第三步,也是很关键的一步,绑定内部的事件->delegateEvents():

    delegateEvents: function(a) {
    	if (a || (a = this.events)) for (var b in f.isFunction(a) && (a = a.call(this)), g(this.el).unbind(".delegateEvents" + this.cid), a) {
    		var c = this[a[b]];
    		if (!c) throw Error('Event "' + a[b] + '" does not exist');
    		var d = b.match(u),
    		e = d[1];
    		d = d[2];
    		c = f.bind(c, this);
    		e += ".delegateEvents" + this.cid;
    		d === "" ? g(this.el).bind(e, c) : g(this.el).delegate(d, e, c)
    	}
    }
    

     查阅源码,我们可以看到此方法会寻找this.events这个属性,并且枚举它。在项目的代码中我们在extend中已经给了它的events属性配置了值:events:{'click .c' : 'click'}并且自定义了关联的click方法(传入了事件对象e)。因此,delegateEvents会把events中的属性进行枚举,逐个地利用zepto的bind方法将我们自己定义的方法(如click)绑定到html(.c)元素上去。值得说明的是,我们在events中绑定的都是el中的元素,也就是说是利用el作为委托的最高级父元素向下捕获事件的。加入A元素不在el这个元素中,那么这样的绑定时无效的。

    最后它执行了初始化函数->initialize();而在扩展的过程当中,我们重写了initialize方法并且在里面调用了自定义render函数,因此在实例化的时候会自动渲染html。

    就这样,一个完整的视图对象就出现了。View能够使我们更加专注于界面逻辑,每一个视图对象中紧密地包含着自己的内部界面逻辑。通过model关联到对应的模型对象,同时它也使得我们在编写代码的时候更加美观。

  • 相关阅读:
    LeetCode Flatten Binary Tree to Linked List
    LeetCode Longest Common Prefix
    LeetCode Trapping Rain Water
    LeetCode Add Binary
    LeetCode Subsets
    LeetCode Palindrome Number
    LeetCode Count and Say
    LeetCode Valid Parentheses
    LeetCode Length of Last Word
    LeetCode Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/constantince/p/4369045.html
Copyright © 2011-2022 走看看