代码改变世界

Javascript MVVM模式前端框架—Knockout 2.1.0系列(7):控制流Control Flow(中篇):理解绑定上下文

2012-07-07 10:37  刺客之家  阅读(2209)  评论(4编辑  收藏  举报

*本文已经同步至索引目录:http://www.cnblogs.com/wbpmrck/archive/2012/05/16/Knockout-introduction.html

前言&基础

最近连续几个礼拜加班,实在是没有心情写博客。今天终于可以休息一下,继续我们的Knockout之旅。

上一篇文章,我们感受了一下control flow的威力,那就是利用viewModel绑定列表元素到DOM上,在这个过程中,由于绑定的数据出现了嵌套,我们使用了一些关键字来实现访问不同的层次对象:

  • $parent:访问当前绑定对象的上一层次对象
  • $data:访问当前绑定对象自身

这些关键字所指向的对象,是基于当前的绑定对象的层次来计算的,当一个绑定发生的时候,ko内部会生成一个Binding Context(绑定上下文),也就是我们今天主要了解的东东,总体来说Binding Context的规则是这样的:

  1. 使用ko.applyBindings方法后,当前绑定上下文就是ViewModel本身(此时你可以直接绑定里面的属性到DOM中)
  2. 使用control flow绑定,会修改当前的绑定上下文到你绑定的对象

下面我们就通过分析一个例子,来了解Binding Context

 

正文

了解Binding Context概念

我们先来看一段代码,是在前面一章中出现过的:

var ViewModel=function() {
    var self = this;
    self.people = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);//people是一个监控数组

    self.removePerson = function() {
        self.people.remove(this);
    };//removePerson是一个定义在ViewModel下的方法
};

这个ViewModel构造函数我把他简化了一下,主要看一下定义的这2个属性:

  1. people:一个监控数组,存放了我们初始化的3个对象,每个对象都只有一个name属性,存放一个名词
  2. removePersion:一个function,用来从people数组中删除一个记录,注意这里传入的参数是this

然后我们看一下Html中如何绑定这个viewmodel:

  <ul data-bind="foreach: people">
                <li>
                    Name: <span data-bind="text: name"> </span>
                    <a href="#" data-bind="click: $parent.removePerson">Remove</a>
                </li>
  </ul>

这里我同样把代码简化了一下,我们只关注这一个foreach绑定:

  1. 首先在ul上,我们使用foreach绑定到viewModel中的people属性(记住他是一个监控数组哦)
  2. 接着在下面的li中,我们队第一个span元素使用text绑定,对象是name属性。
  3. 再下面的a标签,我们使用click绑定,我们希望这个绑定可以调用viewModel中的removePerson方法 

现在我们看Html中是如何实现这些功能的,从中我们可以体会一下Binding Context的存在:

首先看一下现在的对象层次结构

 

  • 首先看foreach绑定,直接指向people这个属性,是因为我们当前的Binding Context是ViewModel自身:

 

  • 接下了由于我们使用了foreach,KO发现你要绑定的是一个数组,就将当前Binding Context指向这个数组

 

  • 再接下来我们要绑定数组中的一个对象的name属性到span上,由于当前的绑定上下文已经是数组了,所以我们可以直接使用数组元素的name属性来完成绑定

到这里,我们发现Binding Context随着Control Flow的使用,一层层向下延展开来,这样有一个好处,就是方便我们进行更细层次的绑定,语法更加简单。因为上下文已经随着foreach的指定而变化,我们只需要关注当前上下文内的哪些属性使我们需要的。

 

访问上层Context

这里我们先考虑一下,如果需要从数组中删除一个记录,那么我们需要调用ViewModel下面的removePerson方法。如果直接使用click绑定到removePerson,行不行呢?从上面我们的分析得知,当前我们的上下文已经转移到了people数组内部,这里面是没有removePerson的方法定义的。(感兴趣的朋友可以自己尝试一下,直接绑定到removePerson,看ko是否报错)。

所以KO为我们提供了一系列的特殊语法,帮助我们“跳出”当前的上下文,去访问其他层次的对象,比如:

  • $parent:访问当前上下文的父元素

好了,这下就明白了为什么需要用“data-bind="click: $parent.removePerson"”这样的方式来绑定removePerson方法了

 

绑定对象&绑定函数的调用对象

细心的朋友应该会发现, 在removePerson函数里,我们从people数组中删除一个元素,使用的参数是this.其实这个this指向的是people的一个元素,也就是{name:'xxx'}对象。当我们通过$parent方法访问到ViewModel这个对象的removePerson方法时,KO内部其实为这个方法的调用指定了一个调用对象(对函数的调用对象概念不清楚的,可以看一下javascript基础),而这个调用对象就是当前绑定到的对象,我这里给他起个名字,叫做“绑定对象”:

  • $data:指向当前Binding到的对象引用,他是Binding Context下的直接属性

在Html中,我们也可以通过$data直接访问当前的绑定对象,在本例中,$data就是指{name:'xxx'}对象.由于KO直接帮我们绑定到的方法:removePerson指定了调用对象,所以我们直接在该方法中使用this关键字就可以访问到$data啦~

 

其他的上下文访问关键字

除了$data和$parent以外,KO还提供了很多关键字来访问不同的上下文:

  • $parents:一个数组,通过0开始的下标依次访问上一层的上下文:$parents[0]就是$parent,$parent[1]是$parent的$parent,依次类推
  • $root:指向ViewModel,也就是绑定上下文的根

 

总结

今天主要介绍了ko中的绑定上下文,这个概念对于我们在比较复杂的页面中使用各种绑定非常有用,大家要好好理解哦~

感谢支持

如果本文对您有帮助的话,请别吝啬手中的推荐票哦~

本博客文章若非标记转载,均为原创,转载请注明出处~