Model - 视图模型

在Cola-UI的Model对象管理三件事:数据、绑定、Action。

  • 数据通常利用Model的get和set方法来读取和写入。
  • 数据绑定通常都是通过DOM指令或控件的绑定表达式来建立。
  • Action通常利用Model的action方法来声明和访问。

Model中的数据

Model本身的结构有点像一个Map,数据存储在各个命名的数据项中。每个数据项的值既可以是string、boolean这样的简单值,也可以是复杂的数据实体和集合。

例如,下面的代码向Model中读写了一个名为name的数据项。

// 设置name数据项的值为"Bob"
model.set("name", "Bob");

// 从Model中读取一个名为name的数据项。
var name = model.get("name");

Model的set()/get()的行为特征与cola.Entity的set()/get()几乎是完全一致的,事实上Model的set()/get()在内部正是通过cola.Entity的set()/get()实现的,因此要更详细的了解这两个方法可以直接参考cola.Entity的set()/get()的说明。

动作

Model除了管理数据之外还可以管理动作。利用Model的action()方法可以为Model定义一到多个Action。具体请参考Action

绑定关系

Model会自动管理由DOM指令或其它方式声明的绑定关系,监听Model中数据的变化,将这些消息按需广播给相应的DOM或数据绑定控件。

建立绑定的方式有如下几种:

DOM指令

如下几种情况都会为DOM节点或DOM节点的属性建立数据绑定关系。

<div c-bind="name"></div>
<div c-style="color:fontColor"></div>

数据绑定控件

Cola-UI中的文本录入框(c-input)、复选框(c-checkbox)、表格(c-table)、表单(c-form)等支持数据绑定的控件本身就支持bind属性,可以直接利用该属性生命数据绑定关系。例如:

new cola.Input({
    bind: "name"
});

当我们利用DOM指令来生命一个控件时,也可以直接通过bind属性来声明数据绑定。例如:

<c-input bind="name"></c-input>

考虑开发人员可以已经用惯了普通DOM节点中的c-bind指令,为了避免让开发人员在定义数据绑定控件是为了究竟应该使用bind还是c-bind为纠结。Cola-UI允许开发人员在这种情况下以c-bind来替代bind。因此,下面例子的作用跟上面使用bind属性的完全一样。

<c-input c-bind="name"></c-input>

属性值的内嵌表达式

如果我们需要用Javascript来声明一个控件的话就无法使用上面的两个方法了声明数据绑定了。这时我们可以使用内嵌的表达式。例如:

new cola.Button({
    caption: "{{name}}"
});

上面的例子将Button的caption属性与name数据项建立的绑定。绑定关系也可以这样来定义...

new cola.Label({
    text: "姓名: {{name}}"
});

子Model

Model对于一个页面而言往往并不是一个唯一的实例,很多情况下Cola-UI都会根据需要创建出主Model的子Model实例,子Model实例可视作是主Model的代理对象。通过子Model我们仍然可以访问主Model中的数据和Action。 最常见的接触到子Model的机会是使用c-repeat指令时和使用Cola的Router功能时。

以下面的示例为例:

<script type="text/javascript">
    cola(function(model) {
        model.set("addresses", [
            { city: "ShangHai" },
            { city: "BeiJing" },
            { city: "ShenZhen" }
        ]);
</script>
<body>
    <ul>
        <li d-repeat="address in addresses">
            <span d-bind="address.city"></span>
        </li>
    </ul>
</body>

在li的每一次迭代过程中,Cola-都会为当前迭代的DOM创建一个新的子Model,这个子Model既可以访问主Model中的所有数据,同时它自己也保存了一项名为address的数据,其值为当前的迭代值。而li中的span元素正是绑定了这个子Model中address,因此才能正确的显示当前的迭代值。

多数情况下,开发者可能并不会感觉到这些子Model的存在,因为完全可以像使用主Model一样使用这些子Model,反正主Model中有的数据和Action,通过子Model一样能拿到。但是我认为开发者仍然需要知道在Cola-的处理过程中大致发生了些什么,以免在某些时刻犯下令人感到莫名其妙的错误。