knockoutjs
KnockoutJS入门指南:模板和更多内容
有四个控制流绑定: foreach
, if
, ifnot
和with
。 这些控件绑定使您可以声明性地定义控制流逻辑,而无需创建命名模板,如下所示。
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可以理解并绑定该语法。这个虚拟元素,就好像您有一个真实的容器元素一样。 这种语法对于if
和with
绑定也有效。
仅当指定的表达式求值为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结构(可能带有重复块或嵌套块)的简便方法。 使用模板有两种主要方法。 第一种,天然模板,是支撑着机构foreach
, if
, with
和其他控制流绑定。 在内部,这些控制流绑定捕获元素中包含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元素调用的回调函数。
![](https://i-blog.csdnimg.cn/blog_migrate/426c9021143b9b1517c29fd16ecb5334.png)
免费学习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创建自定义绑定,这为您提供了很大的灵活性,可以轻松地封装复杂的行为。 -重用的方式。 例如,您可以以自定义绑定的形式创建交互式组件,例如网格,选项卡集等。
敲除绑定包括两种方法: init
和update
。 创建绑定就像使用这两种方法创建对象,然后使用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。
init
和update
功能提供了四个参数。 通常,您将需要关注element
和valueAccessor
参数,因为它们是将视图模型链接到UI的标准方法。 实际上,您不必同时提供init
和update
回调-如果需要,您可以只提供其中之一。
element
参数使您可以直接访问包含绑定的DOM元素。
valueAccessor
参数是使您能够访问传递给绑定的内容的函数。 如果您传递了一个可观察的对象,那么此函数的结果将是该可观察的对象(而不是其值)。 如果在绑定中使用了表达式,则valueAccessor
的结果将是表达式的结果。
allBindingsAccessor
参数使您可以访问同一数据绑定属性中列出的所有其他绑定。 通常用于访问与此绑定交互的其他绑定。 这些绑定可能没有任何关联的代码,它们只是将其他选项传递给绑定的一种方法,除非您选择将具有多个属性的对象传递到主绑定中。 例如, optionsValue
, optionsText
和optionsCaption
是绑定,仅用于将选项传递给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
参数为绑定添加其他选项– scaleUp
和scaleDown
。 我们使用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