(三)Knockout 控制流程

foreach

示例1:迭代数组

foreach binding主要作用于lists或是tables内数据单元的动态绑定。下面是一个简单的例子:

 <table>
          <thead>
            <tr>
              <th>First Name</th>
              <th>Last Name</th>
            </tr>
          </thead>
          <tbody data-bind="foreach: people">
            <tr>
              <td data-bind="text: firstName"></td>
              <td data-bind="text: lastName"></td>
            </tr>
          </tbody>
        </table>
    <script type="text/javascript">
      var myViewModel = {
        people: [
          { firstName: "Chiaki", lastName: "Izumi" },
          { firstName: "Kazusa", lastName: "Touma" },
          { firstName: "Haruki", lastName: "Murakami" }
        ]
      };
      ko.applyBindings(myViewModel);
    </script>

示例2:添加 / 删除的实例

在上述示例中,我们简单的在ko.applybindings中添加了一个数组并将其绑定在一个tbody元素中,我们也可以自定义一个view model来实现这一效果,下面是一个更为复杂一些的例子:

  <h4>People</h4>
    <ul data-bind="foreach: people">
      <li>
        Person at position <span data-bind="text: $index"></span>:
        <span data-bind="text: name"></span>
        <a href="#" data-bind="click: $parent.removePerson">Remove</a>
      </li>
    </ul>
    <button data-bind="click: addPerson">Add</button>
    <script type="text/javascript">
      function MyViewModel() {
        var self = this;

        self.people = ko.observableArray([
          { name: "Chiaki" },
          { name: "Yuki" },
          { name: "Kazusa" }
        ]);

        self.addPerson = function() {
          self.people.push({ name: "New name at " + new Date() });
        };

        self.removePerson = function() {
          self.people.remove(this);
        };
      }

      ko.applyBindings(new MyViewModel());
    </script>

196558-20190122225514446-608975581.png
参数

  • 主要参数
    传递希望迭代的数组。绑定将为每个条目输出一段标记。
    或者,传递一个JavaScript对象文本和一个名为data的属性,该属性是您希望迭代的数组。对象文字还可能具有其他属性,如afterAddincludeDestroyed,有关这些额外选项的详细信息及其使用示例,请参见下面。
    如果您提供的数组是可见的,那么foreach绑定将通过在DOM中添加或删除标记的相应部分来响应数组内容的任何未来更改。

注释1:使用 $data 引用每个数组条目

如上面的示例所示,foreach块中的绑定可以引用数组条目上的属性。 例如,示例1引用了每个数组条目的firstName和lastName属性。
但是,如果您想引用数组条目本身(而不仅仅是它的一个属性),该怎么办?在这种情况下,可以使用特殊的上下文属性$data。在foreach块中,它表示当前项。例如:

<ul data-bind="foreach: months">
  <li>
      The current item is: <b data-bind="text: $data"></b>
  </li>
</ul>
  
<script type="text/javascript">
  ko.applyBindings({
      months: [ 'Jan', 'Feb', 'Mar', 'etc' ]
  });
</script>

196558-20190330130437126-2057776106.png

如果需要,可以在引用每个条目上的属性时使用$data作为前缀。例如,您可以将示例1的部分重写如下

<!-- $data 引用对象每个值-->
<td data-bind="text: $data.firstName"></td>

但您不必这样做,因为firstName在默认情况下将在$data上下文中进行计算。如果数组中的项是被监控的,$data将引用每个监控的值。要引用可观察对象本身,推荐使用$rawData

<!--$rawDat 引用对象本身-->
<td data-bind="text: $rawData.firstName"></td> 

注释2:使用$index、$parent和其他上下文属性

从上面的示例2可以看出,可以使用$index引用当前数组项的从零开始的索引。$index是一个可观察的对象,当项目的索引发生变化时(例如,如果项目被添加到数组中或从数组中删除),$index就会被更新。
类似地,您可以使用$parent 引用来自foreach外部的数据,例如。

   <h1 data-bind="text: blogPostTitle"></h1>
    <ul data-bind="foreach: likes">
        <li>
            <b data-bind="text: name"></b> likes the blog post <b data-bind="text: $parent.blogPostTitle"></b>
        </li>
    </ul>
   
  <script type="text/javascript">
     function AppViewModel() {
    var self = this;

    self.blogPostTitle =ko.observable('你好');

    self.likes = ko.observableArray([
        { name: 'Bert' },
        { name: 'Charles' },
        { name: 'Denise' }
    ]);
}
 
ko.applyBindings(new AppViewModel());
  </script>

196558-20190330133700198-746633163.png

注释3:使用 “as” 的别名为 “foreach” 项目

在注释1中提到,我们能够通过$data来调用foreach绑定的数组本身,但是当我们使用嵌套的foreach,内层foreach如何能够调用外层foreach绑定的数组呢?这时我们可以借由as给外层foreach所绑定的数组定义一个另外的名称,进而在内层foreach中利用此名称来调用外层foreach所绑定的数组。接下来是一个简单的例子:

    <ul data-bind="foreach: { data: person, as: 'person' }">
      <li>
        <ul data-bind="foreach: { data: friends, as: 'friends' }">
          <li>
            <span data-bind="text: person.name"></span>:
            <span data-bind="text: friends"></span>
          </li>
        </ul>
      </li>
    </ul>

    <script>
      var viewModel = {
        person: ko.observableArray([
          { name: "Chiaki", friends: ["Charlie", "Kazusa"] },
          { name: "Kazusa", friends: ["Chiaki", "Charlie"] },
          { name: "Charlie", friends: ["Chiaki", "Kazusa"] }
        ])
      };

      ko.applyBindings(viewModel);
    </script>

252006569548726.png
这个例子中的外层foreach绑定的是person数组,person数组中有一个属性name和另外一个数组firends,在内层foreach中绑定的是数组firends。当我们在内层foreach要调用外层的person数组内的属性时,借由as,使用了person.name来调用。而这里也有一个有趣的情况,就是当一个数组里面只有单纯的元素,比如说friends数组,它的元素并不是object,也就不存在这identifier的问题,这时我们要调用它的元素时,只需要调用数组本身即可,这也就是为什么在之前的示例中如果我们调用绑定的数组本身会返回[object, object]。

这表明,一般情况下,遍历数组中的元素只需要调用数组名(as指定)或是调用$data即可,而碰到那些内部元素是object的时候,我们要调用object内的属性则需要调用相应属性的名称。

另外需要注意的一点就是,as后所跟着的必须是一个字符串(as: "person"而不是as: person)。

注释4:不使用foreach当容器

有些情况下,我们使用foreach的场合会比较复杂,比如说如下的例子:

<ul>
      <li>Header item</li>
      <!-- The following are generated dynamically from an array -->
      <li>Item A</li>
      <li>Item B</li>
      <li>Item C</li>
    </ul>

这种情况下,我们并不知道改在哪个元素内添加foreach。如果是在ul添加的话,我们事先写好的header item便会被覆盖掉,而ul元素内又只能嵌套li元素,添加另一个容器来实现foreach也是不可行的。为了解决这一问题,我们需要使用无容器的控制流语法(containerless control flow syntax),与先前所提到的containerless text syntax类似。一个简单的例子如下:

    <!-- 不使用foreach,使用容器 -->
    <ul>
      <li>Header item</li>
      <!-- ko foreach: people -->
      <li>name: <span data-bind="text: $data"></span></li>
      <!-- /ko -->
    </ul>
    
    <!-- 使用foreach -->
    <ul data-bind="foreach: people">
      <li>Header item</li>
      <li>name: <span data-bind="text: $data"></span></li>
    </ul>

    <script>
      var viewModel = {
        people: ko.observableArray(["Kazusa", "Chiaki", "Yuki"])
      };

      ko.applyBindings(viewModel);
    </script>

196558-20190330135021003-1283964182.png

注释7:处理后所生成的 DOM 元素

当我们需要在生成的DOM元素上运行一些自定义的逻辑时,我们可以用到

  • afterRender
  • afterAdd
  • beforeRemove
  • beforeMove
  • afterMove
    等回调函数。

需要注意的是,这些回调函数仅仅适用于触发与列表的改变有关的动画,如果我们需要对新添加的DOM元素附加一些其他的行为,比如说事件的处理或是第三方的UI控制,将这些行为作为自定义的绑定(custom binding)会更为合适,因为这样设定的行为是与foreach互相独立的。

接下来是一个调用afterAdd的简单的例子,其中用到了jQuery Color plugin

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.js"></script>
<script src="http://code.jquery.com/color/jquery.color-2.1.2.min.js"></script>
<script src="../js/knockout-3.5.0rc2.debug.js"></script>

   <ul data-bind="foreach: { data: people, afterAdd: yellowFadeIn }">
      <li data-bind="text: $data"></li>
    </ul>

    <button data-bind="click: addItem">Add</button>

    <script>
      var viewModel = {
        people: ko.observableArray(["Kazusa", "Chiaki", "Yuki"]),

        yellowFadeIn: function(element, index, data) {
          $(element)
            .filter("li")
            .animate({ backgroundColor: "yellow" }, 200)
            .animate({ backgroundColor: "white" }, 800);
        },

        addItem: function() {
          this.people.push("New person");
        }
      };

      ko.applyBindings(viewModel);
    </script>

196558-20190123001054973-1761884406.gif

以下是对一些回调函数详尽的介绍:

afterRender是在foreach模块初始化或是添加新的元素时触发的,其接受的参数为(为了能够保持愿意,这里用英文显示,下同):

An array of the inserted DOM elements
The data item against which they are being bound
afterAddafterRender类似,不过它只会在新元素添加时触发(foreach初始化的时候并不会触发),它所接受的参数为:

A DOM node being added to the document
The index of the added array element
The added array element
beforeRemove函数会在数组中的某一项被删除时触发。需要注意的是,beforeRemove实际上替代了UI界面对remove所做出的回应,即在beforeRemove函数中如果不对DOM相应的元素进行remove操作,则在页面上的元素是不会被删除的,但是viewModel中的数组相应的元素却已经被删除了。beforeRemove函数接受以下参数:

A DOM node that you should remove
The index of the removed array element
The removed array element
beforeMove函数会在数组中的元素索引发生变化时触发,beforeMove会应用于所有索引产生变化的元素,即假若我们在数组开头插入元素,则其后所有元素都将受到beforeMove回调函数的影响。一个比较常用的做法是通过beforeMove来保存原有元素的坐标以便我们能够在afterMove中控制元素移动的动画。beforeMove函数接受以下参数:

A DOM node that may be about to move
The index of the moved array element
The moved array element
afterMove函数也会在数组中的元素索引发生变化时触发,afterMove会应用于所有索引产生变化的元素,即假若我们在数组开头插入元素,则其后所有元素都将受到afterMove回调函数的影响。afterMove函数接收以下参数:

A DOM node that may have moved
The index of the moved array element
The moved array element
对于回调函数中的beforeafter,我们应该有一个比较清醒的认识。before和after针对的都是UI界面中的元素变化,也就是页面产生变化之前和页面产生变化之后,与此同时,viewModel部分的数组已经发生了变化,正是viewModel部分的数组的变化才触发了before和after所对应的回调函数。

if和ifnot绑定

if binding与visible binding类似。不同之处在于,包含visible binding的元素会在DOM中一直保存,并且该元素相应的data-bind属性会一直保持,visible binding只是利用CSS来触发元素的可见性。另一方面,if binding是物理地增加或删除包含它的元素,并且元素内的data-bind只有在判断语句为真时才生效。

例子1

下面是一个简单的if binding的例子:

    <label>
      <input type="checkbox" data-bind="checked: displayMessage" /> 
      Display message
    </label>

    <div data-bind="if: displayMessage">Here is a message. Astonishing.</div>
    <script type="text/javascript">
      ko.applyBindings({
        displayMessage: ko.observable(false)
      });
    </script>

196558-20190330140536521-618740981.gif

例子2

在下面的例子中,<div>元素对于“Mercury”是空的,但是对于“Earth”是填充的。这是因为 Earth 有一个非空 capital 属性,而 Mercury 的 capital 属性为 null

     <ul data-bind="foreach: planets">
          <li>
              Planet: <b data-bind="text: name"> </b>
              <div data-bind="if: capital">
                  Capital: <b data-bind="text: capital.cityName"> </b>
              </div>
          </li>
      </ul>
      
      <script>
          ko.applyBindings({
              planets: [
                  { name: 'Mercury', capital: null }, 
                  { name: 'Earth', capital: { cityName: 'Barnsley' } }        
              ]
          });
      </script>

重要的是要理解 if 绑定对于使代码正常工作非常重要。没有它,在评估时就会出现错误。“Mercury”上下文中的 capital.cityName ,其中 capitalnull。在JavaScript中,不允许计算空值或未定义值的子属性。
196558-20190330141546452-1726164378.png

无容器

if binding也支持无容器的控制流语法,一个简单的示例如下:

   <label>
      <input type="checkbox" data-bind="checked: displayMessage" /> 
      Display message
    </label>

        <ul>
            <li>Item 1</li>
            <!-- ko if: displayMessage -->
            <li>Message</li>
            <!-- /ko -->
        </ul>

    <div data-bind="if: displayMessage">Here is a message. Astonishing.</div>
    <script type="text/javascript">
      ko.applyBindings({
        displayMessage: ko.observable(false)
      });
    </script>

196558-20190330142216192-1137122847.gif

ifnot

<div data-bind="ifnot: someProperty">...</div>

等价于

<div data-bind="if: !someProperty()">...</div>

with和using绑定

withusing 绑定创建一个新的绑定上下文,以便将后代元素绑定到指定对象的上下文中。(这些绑定之间的区别将在下面的参数中描述。)
当然,您可以任意嵌套使用with绑定以using及其他控制流绑定(如ifforeach )。

例子1:

下面是一个将绑定上下文切换到子对象的非常基本的示例。注意,在 data-bind属性中,没有必要在经纬度前面加上coords。,因为绑定上下文已切换到coords
这里也可以使用 with

     <h1 data-bind="text: city"> </h1>
      <p data-bind="using: coords">
          Latitude: <span data-bind="text: latitude"> </span>,
          Longitude: <span data-bind="text: longitude"> </span>
      </p>
       
      <script type="text/javascript">
          ko.applyBindings({
              city: "London",
              coords: {
                  latitude:  51.5001524,
                  longitude: -0.1262362
              }
          });
      </script>

196558-20190330162235311-331704634.png

例子2

   <form data-bind="submit: getTweets">
      Twitter account:
      <input data-bind="value: twitterName" />
      <button type="submit">Get tweets</button>
    </form>

    <div data-bind="with: resultData">
      <h3>
        Recent tweets fetched at <span data-bind="text: retrievalDate"> </span>
      </h3>
      <ol data-bind="foreach: topTweets">
        <li data-bind="text: text"></li>
      </ol>

      <button data-bind="click: $parent.clearResults">Clear tweets</button>
    </div>

    <script type="text/javascript">
      function AppViewModel() {
        var self = this;
        self.twitterName = ko.observable("@example");
        self.resultData = ko.observable(); // No initial value

        self.getTweets = function() {
          var name = self.twitterName(),
            simulatedResults = [
              { text: name + " What a nice day." },
              { text: name + " Building some cool apps." },
              { text: name + " Just saw a famous celebrity eating lard. Yum." }
            ];

          self.resultData({
            retrievalDate: new Date(),
            topTweets: simulatedResults
          });
        };

        self.clearResults = function() {
          self.resultData(undefined);
        };
      }

      ko.applyBindings(new AppViewModel());
    </script>

从这里例子中,我们可以看出with binding在使用时的几个特点。

  • 当with binding所绑定的binding context为null或是undefined时,包含with binding的元素的所有子元素都将从UI页面中移除。
  • 如果我们需要从parent binding context中获取data或是function,我们可以使用特殊的context properties比如说$parentroot,这部分可以参考The binding context

倘若绑定的binding context是一个observable,包含with binding的元素会随着observable的变化而移除现有的子孙元素并添加一系列隶属于新的binding context的子孙元素。

类似的,with binding也提供无容器的控制流语法,这里省略例子,可以参考if binding等。

with和using区别

如果您提供的表达式包含任何监控的值,则每当这些值发生更改时,将重新计算该表达式。这些绑定在绑定值发生变化时的反应不同:
- 对于with绑定,将清除后代元素,并将标记的新副本添加到文档中,并在新值的上下文中绑定。
- 对于using绑定,后代元素将保留在文档中,并使用新的上下文值重新评估它们的绑定。

附加参数

  • as
    as选项允许为新上下文对象设置别名。虽然您可以使用$data上下文变量引用对象,但是使用as选项为它提供一个更具描述性的名称可能会很有用
<div data-bind="with: currentPerson, as: 'person'"></div>
  • noChildContext
      as选项的默认行为是为提供的对象设置一个名称,同时仍然将内容绑定到对象。但是您可能更愿意保持上下文不变,只设置对象的名称。后一种行为可能是将来版本的击倒的默认行为。若要打开特定绑定,请将noChildContext选项设置为true。当这个选项与as一起使用时,对对象的所有访问都必须通过给定的名称,并且$data将保持设置为外部viewmodel。
      对于using绑定,虽然您可以使用此选项,但使用let绑定通常会更有效和描述性。 而不是 using: currentPerson, as: 'person', noChildContext: true,你可以使用 let: { person: currentPerson }

注释1:无容器

与其他控制流绑定(如if和foreach)一样,可以使用with和using而不使用任何容器元素来承载它。如果您需要在不合法的地方使用这些绑定,仅仅为了保存绑定而引入新的容器元素,那么这是非常有用的。

<ul>
    <li>Header element</li>
    <!-- ko with: outboundFlight -->
        ...
    <!-- /ko -->
    <!-- ko with: inboundFlight -->
        ...
    <!-- /ko -->
</ul>

注释2:为什么使用两个类似的绑定?

当不需要重新呈现后代元素时,他在knockoutjs 3.5中using了绑定来替代with。(参考with和using区别) 因为using重新评估后代绑定而不是重新呈现,每个后代绑定将包含对使用上下文的附加依赖。

component 绑定

component 组件绑定将指定的组件注入元素,并可选地向其传递参数。

示例1:计算字数

      <h4>First instance, without parameters</h4>
      <div data-bind='component: "message-editor"'></div>
       
      <h4>Second instance, passing parameters</h4>
      <div data-bind='component: {
          name: "message-editor",
          params: { initialText: "Hello, world!" }
      }'></div>

    <script type="text/javascript">
      ko.components.register('message-editor', {
        viewModel: function (params) {
          this.text = ko.observable(params && params.initialText || '');
        },
        template: 'Message: <input data-bind="value: text" /> '
          + '(length: <span data-bind="text: text().length"></span>)'
      });

      ko.applyBindings();
    </script>

196558-20190330171346587-645008764.gif
注意:在更现实的情况下,您通常会从外部文件加载组件视图模型和模板,而不是将它们硬编码到注册中。请参见示例和注册文档。

API

有两种方法可以使用组件绑定

  • 速记语法
    如果只传递一个字符串,它将被解释为组件名。然后注入命名组件,而不向其提供任何参数。例子
<div data-bind='component: "my-component"'></div>

简写值也可以被监控到。在本例中,如果组件绑定发生更改,则组件绑定将处理(dispose)旧组件实例,并注入新引用的组件。例子

<div data-bind='component: observableWhoseValueIsAComponentName'></div>
  • 完整语法
    要向组件提供参数,请传递具有以下属性的对象
    • name 要注入的组件的名称。这也是可以观察到的。
    • params 将传递给组件的对象。通常,这是一个包含多个参数的键值对象,通常由组件的viewmodel构造函数接收。
    <div data-bind='component: {
      name: "shopping-cart",
      params: { mode: "detailed-list", items: productsList }
    }'></div>
    请注意,无论何时删除组件(要么是因为名称更改了observable,要么是因为封闭的控制流绑定删除了整个元素),删除的组件被释放( disposed)。

组件生命周期

1.组件加载器被要求提供 viewmodel 工厂和模板
  通常,这是一个异步过程。 它可能涉及对服务器的请求。 对于API一致性,默认情况下Knockout确保加载过程作为异步回调完成,即使组件已经加载并缓存在内存中也是如此。 有关此内容以及如何允许同步加载的更多信息,请参阅控制同步/异步加载
2.组件模板被克隆并注入容器元素
3.如果组件有一个视图模型 viewmodel ,则实例化它
4.视图模型 viewmodel 绑定到视图
5.组件被激活
6.组件被拆除,视图模型被放置

注意1:仅有模板组件

组件通常有视图模型,但不一定非得有。组件可以只指定模板。
在本例中,绑定组件视图的对象是传递给组件绑定的params对象。例子

ko.components.register('special-offer', {
    template: '<div class="offer-box" data-bind="text: productName"></div>'
});

可以注入:

<div data-bind='component: {
     name: "special-offer-callout",
     params: { productName: someProduct.name }
}'></div>

或者,更方便地,作为自定义元素

<special-offer params='productName: someProduct.name'></special-offer>

使用无容器

<!-- ko component: {
    name: "message-editor",
    params: { initialText: "Hello, world!", otherParam: 123 }
} -->
<!-- /ko -->

标记传递给组件

附加组件绑定的元素可能包含进一步的标记。例如

<div data-bind="component: { name: 'my-special-list', params: { items: someArrayOfPeople } }">
    <!-- Look, here's some arbitrary markup. By default it gets stripped out
         and is replaced by the component output. -->
    The person <em data-bind="text: name"></em>
    is <em data-bind="text: age"></em> years old.
</div>

尽管该元素中的DOM节点将被删除,并且默认情况下不进行绑定,但它们不会丢失。相反,它们被提供给组件(在本例中是my-special-list),组件可以按照自己的意愿将它们包含在输出中。
如果您想要构建表示容器UI元素的组件,例如网格、列表、对话框或选项卡集,这是非常有用的,因为这些元素需要将任意标记注入并绑定到公共结构中。有关自定义元素的完整示例,它也可以在没有使用上面所示语法的自定义元素的情况下工作。

    <!-- This could be in a separate file -->
    <template id="my-special-list-template">
      <h3>Here is a special list</h3>

      <ul data-bind="foreach: { data: myItems, as: 'myItem' }">
        <li>
          <h4>Here is another one of my special items</h4>
          <!-- ko template: { nodes: $componentTemplateNodes, data: myItem } --><!-- /ko -->
        </li>
      </ul>
    </template>

    <my-special-list params="items: someArrayOfPeople">
      <!-- Look, I'm putting markup inside a custom element -->
      The person <em data-bind="text: name"></em> is
      <em data-bind="text: age"></em> years old.
    </my-special-list>

    <script type="text/javascript">
      ko.components.register("my-special-list", {
        template: { element: "my-special-list-template" },
        viewModel: function(params) {
          this.myItems = params.items;
        }
      });

      ko.applyBindings({
        someArrayOfPeople: ko.observableArray([
          { name: "Lewis", age: 56 },
          { name: "Hathaway", age: 34 }
        ])
      });
    </script>

196558-20190330174903646-522336549.png

转载于:https://www.cnblogs.com/tangge/p/10306627.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个文档是我自己原创制作的,在别的网上肯定是没有的。 而且做得非常好看,和非常准确。 如果下载的人多,将会把中英文对照的版本也上传。 Knockout是一个以数据模型(data model)为基础的能够帮助你创建富文本,响应显示和编辑用户界面的JavaScript类库。任何时候如果你的UI需要自动更新(比如:更新依赖于用户的行为或者外部数据源的改变),KO能够很简单的帮你实现并且很容易维护。 重要特性: 优雅的依赖追踪 - 不管任何时候你的数据模型更新,都会自动更新相应的内容。 Elegant dependency tracking - automatically updates the right parts of your UI whenever your data model changes. 声明式绑定 - 浅显易懂的方式将你的用户界面指定部分关联到你的数据模型上。 Declarative bindings - a simple and obvious way to connect parts of your UI to your data model. You can construct a complex dynamic UIs easily using arbitrarily nested binding contexts. 轻易可扩展 - 几行代码就可以实现自定义行为作为新的声明式绑定。 Trivially extensible - implement custom behaviors as new declarative bindings for easy reuse in just a few lines of code. 额外的好处: 纯JavaScript类库 – 兼容任何服务器端和客户端技术 Pure JavaScript library - works with any server or client-side technology 可添加到Web程序最上部 – 不需要大的架构改变 Can be added on top of your existing web application - without requiring major architectural changes 简洁的 - Gzip之前大约25kb Compact - around 13kb after gzipping 兼容任何主流浏览器 - (IE 6+、Firefox 2+、Chrome、Safari、其它) Works on any mainstream browser - (IE 6+, Firefox 2+, Chrome, Safari, others) 采用行为驱动开发 - 意味着在新的浏览器和平台上可以很容易通过验证。 Comprehensive suite of specifications - (developed BDD-style) means its correct functioning can easily be verified on new browsers and platforms 开发人员如果用过Silverlight或者WPF可能会知道KO是MVVM模式的一个例子。如果熟悉 Ruby on Rails 或其它MVC技术可能会发现它是一个带有声明式语法的MVC实时form。换句话说,你可以把KO当成通过编辑JSON数据来制作UI用户界面的一种方式… 不管它为你做什么 Developers familiar with Ruby on Rails, ASP.NET MVC, or other MV* technologies may see MVVM as a real-time form of MVC with declarative syntax. In another sense, you can think of KO as a general way to make UIs for editing JSON data… whatever works for you :) OK, 如何使用它? 简单来说:声明你的数据作为一个JavaScript 模型对象(model object),然后将DOM 元素或者模板(templates)绑定到它上面. The quickest and most fun way to get started is by working through the interactive tutorials. Once you’ve got to grips with the basics, explore the live examples and then have a go with it in your own project. KO和jQuery (或Prototype等)是竞争关系还是能一起使用? 所有人都喜欢jQuery! 它是一个在页面里操作元素和事件的框架,非常出色并且易使用,在DOM操作上肯定使用jQuery,KO解决不同的问题。 Everyone loves jQuery! It’s an outstanding replacement for the clunky, inconsistent DOM API we had to put up with in the past. jQuery is an excellent low-level way to manipulate elements and event handlers in a web page. I certainly still use jQuery for low-level DOM manipulation. KO solves a different problem. 如果页面要求复杂,仅仅使用jQuery需要花费更多的代码。 例如:一个表格里显示一个列表,然后统计列表的数量,Add按钮在数据行TR小于5调的时候启用,否则就禁用。jQuery 没有基本的数据模型的概念,所以需要获取数据的数量(从table/div或者专门定义的CSS class),如果需要在某些SPAN里显示数据的数量,当添加新数据的时候,你还要记得更新这个SPAN的text。当然,你还要判断当总数>=5条的时候禁用Add按钮。 然后,如果还要实现Delete功能的时候,你不得不指出哪一个DOM元素被点击以后需要改变。 As soon as your UI gets nontrivial and has a few overlapping behaviors, things can get tricky and expensive to maintain if you only use jQuery. Consider an example: you’re displaying a list of items, stating the number of items in that list, and want to enable an ‘Add’ button only when there are fewer than 5 items. jQuery doesn’t have a concept of an underlying data model, so to get the number of items you have to infer it from the number of TRs in a table or the number of DIVs with a certain CSS class. Maybe the number of items is displayed in some SPAN, and you have to remember to update that SPAN’s text when the user adds an item. You also must remember to disable the ‘Add’ button when the number of TRs is 5. Later, you’re asked also to implement a ‘Delete’ button and you have to figure out which DOM elements to change whenever it’s clicked. Knockout的实现有何不同? 使用KO非常简单。将你的数据描绘成一个JavaScript数组对象myItems,然后使用模板(template)转化这个数组到表格里(或者一组DIV)。不管什么时候数组改变, UI界面也会响应改变(不用指出如何插入新行或在哪里插入),剩余的工作就是同步了。例如:你可以声明绑定如下一个SPAN显示数据数量(可以放在页面的任何地方,不一定非要在template里): It’s much easier with KO. It lets you scale up in complexity without fear of introducing inconsistencies. Just represent your items as a JavaScript array, and then use a foreach binding to transform this array into a TABLE or set of DIVs. Whenever the array changes, the UI changes to match (you don’t have to figure out how to inject new TRs or where to inject them). The rest of the UI stays in sync. For example, you can declaratively bind a SPAN to display the number of items as follows: There are <span data-bind="text: myItems().count"></span> items就是这些!你不需要写代码去更新它,它的更新依赖于数组myItems的改变。同样, Add按钮的启用和禁用依赖于数组 myItems 的长度,如下: That’s it! You don’t have to write code to update it; it updates on its own when the myItems array changes. Similarly, to make the ‘Add’ button enable or disable depending on the number of items, just write: <button data-bind="enable: myItems().count < 5">Add</button>之后,如果你要实现Delete功能,不必指出如何操作UI元素,只需要修改数据模型就可以了。 Later, when you’re asked to implement the ‘Delete’ functionality, you don’t have to figure out what bits of the UI it has to interact with; you just make it alter the underlying data model. 总结:KO没有和jQuery或类似的DOM 操作API对抗竞争。KO提供了一个关联数据模型和用户界面的高级功能。KO本身不依赖jQuery,但是你可以一起同时使用jQuery, 生动平缓的UI改变需要真正使用jQuery。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值