knockoutjs_KnockoutJS入门指南:第3部分

knockoutjs

KnockoutJS入门指南:模板和更多内容

有四个控制流绑定: foreachififnotwith 。 这些控件绑定使您可以声明性地定义控制流逻辑,而无需创建命名模板,如下所示。

foreach绑定为数组中的每个条目复制标记的一部分,并将该标记的每个副本绑定到相应的数组项。 这适用于呈现列表或表。 如果您的数组是可观察的数组,则每当您以后添加或删除数组条目时,绑定将通过插入或删除列表项或表行的更多副本来更新UI以使其匹配,而不会影响任何其他DOM元素。 请参见以下示例:

<table>
 <thead>
  <tr><th>Title</th><th>Author</th></tr>
 </thead>
 <tbody data-bind="foreach: books">
  <tr>
   <td data-bind="text: title"></td>
   <td data-bind="text: author"></td>      
  </tr>
 </tbody>
</table>

<script type="text/javascript">
  function viewModel() {
   var self = this;
   self.books = ko.observableArray([
     { title: 'The Secret', author: 'Rhonda Byrne' },
     { title: 'The Power', author: 'Rhonda Byrne' },
     { title: 'The Magic', author: 'Rhonda Byrne' }
   ]);
  }
  ko.applyBindings(new viewModel());    
</script>

在这里,将为books数组中的每个数组条目自动创建一个表行。

有时,您可能需要引用数组条目本身,而不仅仅是其属性之一。 在这种情况下,可以使用伪变量$data 。 在foreach块中使用时,表示“当前项目”。

<ul data-bind="foreach: daysOfWeek">
 <li>
 <span data-bind="text: $data"></span>
 </li>
</ul>

<script type="text/javascript">
function viewModel() {
  var self = this;
  self.daysOfWeek = ko.observableArray([
   'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
  ]);
};

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

这将列出一周中的所有天,而无需分别重复每个项目的代码。

在淘汰赛中,您可以根据需要嵌套任意数量的控制流绑定。 并且当您这样做时,通常需要备份层次结构并从父上下文访问数据或函数。 在这种情况下,您可以使用以下伪变量:

$parent –表示当前foreach块之外的数据项

$parents –是一个数组,表示来自所有外部控制流范围的数据项。 $parents[0]$parent相同。 $parents[1]代表祖父母控制流范围中的项目,依此类推。

$root –表示最外部的控制流范围中的项目。 通常,这是您的顶级视图模型对象。

在下面的示例中,我们使用$parent伪变量,以便从books数组中正确删除一个book项目:

<table>
 <thead>
  <tr><th>Title</th><th>Author</th></tr>
 </thead>
 <tbody data-bind="foreach: books">
  <tr>
   <td data-bind="text: title"></td>
   <td data-bind="text: author"></td>
   <td><a href="#" data-bind="click: $parent.removeBook">Remove</a></td>
  </tr>
 </tbody>
</table>

<script type="text/javascript">
  function viewModel() {
   var self = this;
   self.books = ko.observableArray([
     { title: 'The Secret', author: 'Rhonda Byrne' },
     { title: 'The Power', author: 'Rhonda Byrne' },
     { title: 'The Magic', author: 'Rhonda Byrne' }
   ]);

  self.removeBook = function() {
   self.books.remove(this);
  }
  }
  ko.applyBindings(new viewModel());    
</script>

在某些情况下,您可能希望复制标记的一部分,但没有任何容器元素可在其上放置foreach绑定。 然后,您可以使用以下语法:

<ul>
<li><strong>Days of week:</strong></li>
 <!-- ko foreach: daysOfWeek -->
 <li>
  <span data-bind="text: $data"></span>
 </li>
 <!-- /ko -->
</ul>

<script type="text/javascript">
function viewModel() {
  var self = this;
  self.daysOfWeek = ko.observableArray([
   'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
  ]);
};

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

在此示例中,您不能使用普通的foreach绑定。 如果将其放在<ul>这将复制标题项,并且如果要在<ul>内放置另一个容器,则不能,因为在<ul>内仅允许<li>元素。 解决方案是使用无容器控制流语法,其中<!-- ko --><!-- /ko -->注释定义一个“虚拟元素”,其中包含标记,Knockout可以理解并绑定该语法。这个虚拟元素,就好像您有一个真实的容器元素一样。 这种语法对于ifwith绑定也有效。

仅当指定的表达式求值为true时, if绑定才会使一部分标记出现在文档中。 然后,包含的标记将出现在文档中,并将应用其上的任何数据绑定属性。 另一方面,如果表达式的计算结果为false,则包含的标记将从文档中删除,而无需先对其应用任何绑定。

<label><input type="checkbox" data-bind="checked: showList" />Show me list</label>
<ul data-bind="if: showList">
  <li>Item</li>
  <li>Item</li>
  <li>Item</li>
</ul>

<script type="text/javascript">
   function viewModel() {
    var self = this;
    self.showList = ko.observable(false);
   }
  ko.applyBindings(new viewModel());    
</script>

with绑定将创建一个新的绑定上下文,以便将后代元素绑定到指定对象的上下文中。 您想要用作绑定后代元素的上下文的对象。 如果您提供的表达式的值为空或未定义,则后代元素将完全不会绑定,而是会从文档中删除。 with绑定将数据上下文更改为您指定的任何对象。 在处理具有多个父子关系的对象图时,这特别有用。

<p data-bind="text: book"> </p> 
<ul data-bind="with: details">
 <li>Category: <span data-bind="text: category"> </span></li>
 <li>Author: <span data-bind="text: author"> </span></li>
 <li>Publisher: <span data-bind="text: publisher"> </span></li>
</ul>

<script type="text/javascript">
  function viewModel() {
   var self = this;
   self.book = ko.observable('The Secret');
   self.details = ko.observable({category: 'Psychology', author: 'Rhonda Byrne', publisher: 'Simon & Schuster Ltd'});
  }
 ko.applyBindings(new viewModel());    
</script>

模板化

template绑定使用呈现模板的结果填充关联的DOM元素。 模板是根据视图模型数据构建复杂的UI结构(可能带有重复块或嵌套块)的简便方法。 使用模板有两种主要方法。 第一种,天然模板,是支撑着机构foreachifwith和其他控制流绑定。 在内部,这些控制流绑定捕获元素中包含HTML标记,并将其用作模板以针对任意数据项进行呈现。 此功能内置在Knockout中,不需要任何外部库。 您可以在此处查看创建模板的基本方案:

<div data-bind="template: 'myTemplate'"></div>

<script type="text/html" id="myTemplate">
// template code here
</script>

在下面的示例中,您可以看到如何使用它:

<div data-bind="template: 'book-template'"></div>

<script type="text/html" id="book-template">  
  <h3 data-bind="text: title"></h3>
  <p>Written by: <span data-bind="text: author"></span></p>
</script>

<script type="text/javascript">
   function viewModel() {
    var self = this;
    self.title = ko.observable('The Secret')
    self.author = ko.observable('Rhonda Byrne')
   }
 ko.applyBindings(new viewModel());    
</script>

在这里,我们必须使用一个等于模板名称的id来将模板绑定到标记的其余部分。 在这种情况下,它是“书模板”。

代替使用上述简短的语法,我们可以将更多参数传递给模板绑定,这将使我们对最终输出具有更精确的控制。

//syntax: <div data-bind="template: { name: 'myTemplate', data: myData, afterRender: myLogic }"></div>

<div data-bind="template: { name: 'book-template', data: bestseller, afterRender: msg }"></div>

//template here

<script type="text/javascript">
   function MyViewModel() {
    var self = this;
    self.bestseller = { title: 'The Secret', author: 'Rhonda Byrne' };
    self.ordinary = {title: 'Some Name', author: 'Some Author'};
    self.msg = function(elements) {
      alert('Hip Hip Hooray!!! :)'); 
    }
   }
 ko.applyBindings(new MyViewModel());    
</script>

在这里, name是包含您要渲染的模板的元素的ID。 data是要作为模板渲染的数据提供的对象; afterRender是要针对呈现的DOM元素调用的回调函数。

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

以下示例等效于foreach绑定。 在这里, foreach作为参数传递给template绑定。

//syntax: <div data-bind="template: { name: 'myTemplate', foreach: myArray }"></div>

<div data-bind="template: { name: 'book-template', foreach: books }"></div>

//template here

<script type="text/javascript">
   function MyViewModel() {
    var self = this;
    self.books = [
    { title: 'The Secret', author: 'Rhonda Byrne' },
    { title: 'The Power', author: 'Rhonda Byrne' }
    ]
   }
 ko.applyBindings(new MyViewModel());    
</script>

通过将匿名模板直接嵌入到您使用foreach绑定的元素内,您可以获得完全相同的结果:

<div data-bind="foreach: books">  
  <h3 data-bind="text: title"></h3>
  <p>Written by: <span data-bind="text: author"></span></p>
</div>

使用模板的第二种方法是将Knockout连接到第三方模板引擎。 淘汰赛会将模型值传递给外部模板引擎,并将生成的标记字符串注入到文档中。 对于使用jquery.tmpl强调模板引擎实例检查文档

扩展可观察

可观察的观察项提供了支持读取/写入值并在值更改时通知订阅者所必需的基本功能。 但是,在某些情况下,您可能希望向可观察对象添加其他功能,例如向可观察对象添加其他属性。 敲除扩展器提供了一种简单而灵活的方式来实现此目的。

创建扩展程序需要向ko.extenders对象添加一个功能。 该函数将可观察对象本身作为第一个参数,并将第二个参数中的所有选项作为参数。 然后,它可以返回可观察值,也可以返回某种新值,例如以某种方式使用原始可观察值的计算可观察值。

现在,我们将创建一个可观察的扩展程序,它将添加显示提示消息的功能。

<input data-bind='value: name, hasfocus: name.on' />
<span data-bind="visible: name.on, text: name.hint"></span>
<br />
<input data-bind='value: pass, hasfocus: pass.on' />
<span data-bind="visible: pass.on, text: pass.hint"></span>

<script type="text/javascript">

// begin observable extender
ko.extenders.hints = function(target, hint) {
 target.on = ko.observable() 
 target.hint = ko.observable()

 function showHint(value){
  target.on(value ? false : true);
  target.hint(value ? "" : hint);
 }

 showHint(target());

 return target;
}; 
// end observable extender

 function viewModel() {
  var self = this;
  self.name = ko.observable().extend({hints: 'Type your name here'})
  self.pass = ko.observable().extend({hints: 'Type your password here'})
 };
ko.applyBindings(new viewModel());
</script>

自定义绑定

Knockout的内置绑定使您能够处理大多数绑定方案,但是如果遇到未涵盖的特殊绑定方案,则可以使用Knockout创建自定义绑定,这为您提供了很大的灵活性,可以轻松地封装复杂的行为。 -重用的方式。 例如,您可以以自定义绑定的形式创建交互式组件,例如网格,选项卡集等。

敲除绑定包括两种方法: initupdate 。 创建绑定就像使用这两种方法创建对象,然后使用ko.bindingHandlers使用Knockout注册该对象一样简单,如下所示。

ko.bindingHandlers.yourBindingName = {   
  init: function(element, valueAccessor, allBindingsAccessor, viewModel) {

  },   
  update: function(element, valueAccessor, allBindingsAccessor, viewModel) {

  } 
};

// once created, you can use your custom binding in similar way as any built-in binding
<div data-bind="yourBindingName: someValue"> </div>

init函数将仅在第一次为此元素评估绑定时运行。 这通常用于运行一次性初始化代码或连接事件处理程序,使您可以基于UI中触发的事件来更新视图模型。

update功能提供了一种方法,用于在关联的可观察对象被修改时做出响应。 通常,这用于根据视图模型的更改来更新UI。

initupdate功能提供了四个参数。 通常,您将需要关注elementvalueAccessor参数,因为它们是将视图模型链接到UI的标准方法。 实际上,您不必同时提供initupdate回调-如果需要,您可以只提供其中之一。

element参数使您可以直接访问包含绑定的DOM元素。

valueAccessor参数是使您能够访问传递给绑定的内容的函数。 如果您传递了一个可观察的对象,那么此函数的结果将是该可观察的对象(而不是其值)。 如果在绑定中使用了表达式,则valueAccessor的结果将是表达式的结果。

allBindingsAccessor参数使您可以访问同一数据绑定属性中列出的所有其他绑定。 通常用于访问与此绑定交互的其他绑定。 这些绑定可能没有任何关联的代码,它们只是将其他选项传递给绑定的一种方法,除非您选择将具有多个属性的对象传递到主绑定中。 例如, optionsValueoptionsTextoptionsCaption是绑定,仅用于将选项传递给options绑定。

viewModel参数将提供对整体视图模型的访问,以进行模板外部的绑定。 在模板内部,这将设置为绑定到模板的数据。 例如,当使用模板绑定的foreach选项时, viewModel参数将设置为通过模板发送的当前数组成员。 在大多数情况下, valueAccessor会为您提供所需的数据,但是如果在调用/应用函数时需要将对象作为目标,则viewModel参数特别有用。

在下面的示例中,我们将创建一个自定义绑定,该绑定可在焦点对准文本区域时缩放。

<textarea data-bind="scaleOnFocus: scaleArea, scaleUp: {height: '200', width: '400'}, scaleDown: {height: '15', width: '150'}"></textarea>

<script type="text/javascript">

// begin custom binding
ko.bindingHandlers.scaleOnFocus = {

 init: function(element, valueAccessor) {
  $(element).focus(function() {
   var value = valueAccessor();
   value(true);
  });
  $(element).blur(function() {
   var value = valueAccessor();
   value(false);
  });     
 },

 update: function(element, valueAccessor, allBindingsAccessor) {
  var value = valueAccessor();
  var allBindings = allBindingsAccessor();
  var up = allBindings.scaleUp;
  var down = allBindings.scaleDown;
   if (ko.utils.unwrapObservable(value))
    $(element).animate(up);
   else 
    $(element).animate(down);
 }
};
// end custom binding

function viewModel() {
 var self = this;
 self.scaleArea = ko.observable()
};

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

首先,在init函数中,我们声明当element处于焦点时,其值将设置为true,反之亦然。 然后,在update函数中,我们使用allBindingAccessor参数为绑定添加其他选项– scaleUpscaleDown 。 我们使用ko.utils.unwrapObservable获取当前绑定的值,并检查其是否设置为true。 如果是这样,则将DOM元素按比例放大,否则按比例缩小。

最后,让我们看一个结合了提示可观察的扩展程序和scaleOnFocus自定义绑定的示例:

<input data-bind='value: name, hasfocus: name.on' />
<span data-bind="visible: name.on, text: name.hint"></span>
<br />
<input data-bind='value: email, hasfocus: email.on' />
<span data-bind="visible: email.on, text: email.hint"></span>
<br />
<textarea data-bind="value: msg.hint, scaleOnFocus: scaleArea, scaleUp: {height: '200', width: '400'}, scaleDown: {height: '50', width: '150'}"></textarea>

<script type="text/javascript">
ko.extenders.hints = function(target, hint) {
 target.on = ko.observable() 
 target.hint = ko.observable()

 function showHint(value){
  target.on(value ? false : true);
  target.hint(value ? "" : hint);
 }

 showHint(target());

 return target;
}; 

ko.bindingHandlers.scaleOnFocus = {

 init: function(element, valueAccessor) {
  $(element).focus(function() {
   var value = valueAccessor();
   value(true);
  });
  $(element).blur(function() {
   var value = valueAccessor();
   value(false);
  });     
 },

 update: function(element, valueAccessor, allBindingsAccessor) {
  var value = valueAccessor();
  var allBindings = allBindingsAccessor();
  var up = allBindings.scaleUp;
  var down = allBindings.scaleDown;
   if (ko.utils.unwrapObservable(value))
    $(element).animate(up);
   else 
    $(element).animate(down);
 }
};

function viewModel() {
 var self = this;
 self.name = ko.observable().extend({hints: 'Type your full name'})
 self.email = ko.observable().extend({hints: 'Type a valid email'})
 self.msg = ko.observable().extend({hints: 'Leave a message...'})
 self.scaleArea = ko.observable()
};
ko.applyBindings(new viewModel());
</script>

您可以将提示observable和scaleOnFocus绑定放在单独的文件中,然后将其包括在主文件中。 这使代码模块化,并允许您随时使用它。

就是这样,伙计们! 希望您喜欢这个系列。 现在,您已经掌握了所有必要的知识,可以开始并继续学习和尝试淘汰赛。 有关更全面的示例和教程,您可以转到Knockout网站,我建议您这样做。

翻译自: https://www.sitepoint.com/beginners-guide-to-knockoutjs-part-3/

knockoutjs

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值