<div> You've clicked <span data-bind="text: numberOfClicks"></span> times <button data-bind="click: incrementClickCounter">Click me</button> </div> <script src="../../lib/knockout/knockout-3.4.0.js"></script> <script type="text/javascript"> var viewModel = { numberOfClicks: ko.observable(0), incrementClickCounter: function() { var previousCount = this.numberOfClicks(); this.numberOfClicks(previousCount + 1); } }; ko.applyBindings(viewModel); </script>
这里须要注意的是numberOfClicks的修改方法。javascript
click binding不只仅能够绑定viewModel中的方法,也能够绑定其余任意的方法。html
在调用click binding的处理函数时,咱们能够给它传递一个参数做为当前做用的项(current item),这种操做每每在处理集合或是数组时很是有用。java
<ul data-bind="foreach: people"> <li> <span data-bind="text: $data"></span> <button data-bind="click: $parent.removePerson">Remove</button> </li> </ul> <script> function MyViewModel() { var self = this; self.people = ko.observableArray(["Kazusa", "Chiaki", "Charlie"]); self.removePerson = function(person) { self.people.remove(person); }; } ko.applyBindings(new MyViewModel()); </script>
注意上例中关于$parent的使用,在使用foreach binding或是with binding时,必定要明确本身可以直接调用的viewModelProperty的范围,若是在更高的层次,则要考虑使用$parent或是$root这样的前缀。express
在某些时候,咱们须要获取与click事件相关联的DOM event object(提及来听绕口,我以为能够直接就说是包含click在内的可以触发相应绑定的处理函数的事件),KO将这个事件做为处理函数的第二个参数,好比说咱们但愿在按下shift键的clik与通常的click有所区别,则能够利用这一参数在处理函数中进行区分。数组
<button data-bind="click: myFunction"> Click me </button> <script type="text/javascript"> var viewModel = { myFunction: function(data, event) { if (event.shiftKey) { //do something different when user has shift key down } else { //do normal action } } }; ko.applyBindings(viewModel); </script>
若是咱们须要传递更多的参数,有如下两种方式:浏览器
<!-- 方法1 --> <button data-bind="click: function(data, event) { myFunction('param1', 'param2', data, event) }"> Click me </button> <!-- 方法2 --> <button data-bind="click: myFunction.bind($data, 'param1', 'param2')"> Click me </button>
在默认状况下,使用click binding会屏蔽掉原先click的默认功能,好比对于一个a元素,在使用click binding以后,并不会跳转到href所描述的地址。若是咱们但愿恢复默认的功能,只须要在click binding所绑定的处理函数的最后返回一个true
便可。app
在这种状况下,若是咱们点击页面上的button,则会依次触发function三、function二、function1。为了防止这种现象,咱们能够在data-bind后附加clickBubble:false
来阻止click事件继续向上传递,好比说咱们将代码改为这样:异步
<div data-bind="click: function1"> <div data-bind="click: function2"> <button data-bind="click: function3, clickBubble: false">Click me</button> </div> </div>
这样一来就只会触发function3。而若是咱们是在function2后面添加,则只会依次触发function3和function2,以此类推函数
event binding主要用于为指定的事件添加相应的处理函数,能够做用于任意事件,包括keypress、mouseover、mouseout等(也包括以前提到的click,根据后面的描述,click binding的内部机理其实就是event binding,不过为什么要把二者分开有待研究)。ui
<div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }"> Mouse over me </div> <div data-bind="visible: detailsEnabled">Details</div> <script> function MyViewModel() { var self = this; self.detailsEnabled = ko.observable(false); self.enableDetails = function() { self.detailsEnabled(true); }; self.disableDetails = function() { self.detailsEnabled(false); }; } ko.applyBindings(new MyViewModel()); </script>
event binding的参数应当是一个object,在该object中,属性名为指定的事件的名称,值为触发的处理函数。该处理函数能够是viewModel中定义的函数,也能够是其余任意object内的函数。
在调用event binding的处理函数时,咱们能够给它传递一个参数做为当前做用的项(current item),这种操做每每在处理集合或是数组时很是有用。
在某些时候,咱们须要获取与事件相关联的DOM event object(提及来听绕口,我以为能够直接就说是包含事件在内的可以触发相应绑定的处理函数的事件),KO将这个事件做为处理函数的第二个参数,好比说咱们但愿在按下shift键时的该事件与通常的事件有所区别,则能够利用这一参数在处理函数中进行区分。
<div data-bind="event: { mouseover: myFunction }"> Mouse over me </div> <script type="text/javascript"> var viewModel = { myFunction: function(data, event) { if (event.shiftKey) { //do something different when user has shift key down } else { //do normal action } } }; ko.applyBindings(viewModel); </script>
若是咱们须要传递更多的参数,有如下两种方式:
<!-- 方法1 --> <div data-bind="event: { mouseover: function(data, event) { myFunction('param1', 'param2', data, event) } }"> Mouse over me </div> <!-- 方法2 --> <button data-bind="event: { mouseover: myFunction.bind($data, 'param1', 'param2') }"> Click me </button>
在默认状况下,使用event binding会屏蔽掉原先event所触发的默认功能。若是咱们但愿恢复默认的功能,只须要在event binding所绑定的处理函数的最后返回一个true
便可。
在某些时候,咱们的html部分可能会存在嵌套的event binding的状况,具体实例能够参考以前click binding部分的内容,此时也能够利用相似的方法来阻止这种状况,不过不一样的在于书写bubble的格式,一个简单的例子:
<div data-bind="event: { mouseover: myDivHandler }"> <button data-bind="event: { mouseover: myButtonHandler }, mouseoverBubble: false"> Click me </button> </div>
能够看出,bubble与event是两种不一样的binding,因此bubble不该该出如今event binding的参数中。
enable binding每每做用于form elements,好比input、select和textarea等。包含enable binding的DOM元素会依照enable binding参数的真假来决定本身是否可用。
<p> <input type="checkbox" data-bind="checked: hasCellphone" /> I have a cellphone. </p> <p> Your cellphone number: <input type="text" data-bind="value: cellphoneNumber, enable: hasCellphone" /> </p> <script> function MyViewModel() { var self = this; self.cellphoneNumber = ""; self.hasCellphone = ko.observable(false); } ko.applyBindings(new MyViewModel()); </script>
enable binding的参数能够是viewModel中的函数,也能够是任意的javascript判断语句。若是说参数是一个observable,则每当该observable变化时,UI就会当即更新相应元素的enable状态,不然,UI只会对元素的enable状态设置一次。
至于disable binding的使用方法彻底能够参照enable binding,二者的效果只是恰好相反罢了。
参照 enable binding...
使用方法彻底能够参照enable binding,二者的效果只是恰好相反罢了。
value binding通常适用于input、select、textarea等form elements中,可以将view model中的属性和相关联的DOM element的值(value)链接起来。通常状况下,当用户修改form域中的值时,KO会更新相关联的view model中的属性的值;一样的,当view model中的属性值发生变化时,KO也会更新页面中相关联的form域内的值。
注意:当咱们处理checkboxs或是radio buttons时,咱们通常使用checked binding来读写元素的checked状态,而不是使用value binding。
<p>Login name: <input data-bind="value: userName" /></p> <p>Password: <input type="password" data-bind="value: userPassword" /></p> <script type="text/javascript"> var viewModel = { userName: ko.observable(), // Initially blank userPassword: ko.observable("abc"), // Prepopulate }; ko.applyBindings(viewModel); </script>
KO会将相应的元素的value设置为参数的值,且任意以前的value都会被覆盖掉。若是参数是一个observable,则binding会在参数值改变的时候更新元素中的value,不然,UI只会设置一次value的内容,之后再也不更新。
当用户修改form域内使用了value binding的元素的value时,KO会相应地更新view model内被绑定的属性,默认状况下这实际上是借由change event触发的,也就是在用户修改了这个值并转而关注另外一个DOM节点的时候触发。可是咱们也可以借由 valueUpdate
这一参数来经过其余的事件触发更新。经常使用的参数包括"input", "keyup", keypress", "afterkeydown"等。
附加参数
change
” (默认值) - 当失去焦点的时候更新view model的值,或者是<select>
元素被选择的时候。input
"- 更新你的视图模型的值<input>
或<textarea>
元件变化。注意 , 此事件的合理的现代浏览器 ( 例如 IE 9 +) 。keyup
" 当用户敲完一个字符之后当即更新view model.keypress
"- 当用户正在敲一个字符但没有释放键盘的时候就当即更新view model。不像 keyup,这个更新和keydown是同样的。afterkeydown
"- 当用户开始输入字符的时候就更新view model。主要是捕获浏览器的keydown事件或异步handle事件。valueAllowUnset
仅适用于使用value控制选择<select>
元件。对其余元素没有影响。若是咱们但愿绑定<input type="text">
或是<textarea>
以获取view model的即时更新,textInput binding相比于value binding会提供更好的支持
KO会为select元素提供特殊的支持,value binding协同options binding可以让咱们读写任意的javascript object,而不只仅是字符串的值。更为详尽的内容能够参阅the options binding和the selectedOptions binding。这里还涉及到另外一个参数valueAllowUnset的问题,待研究了options binding等之后再进行补充。
<p> Select a country: <select data-bind="options: countries, optionsCaption: 'Choose one...', value: selectedCountry, valueAllowUnset: true"></select> </p> <script type="text/javascript"> var viewModel = { countries: ['Japan', 'Bolivia', 'New Zealand'], selectedCountry: ko.observable('Bolivia') //默认值 }; ko.applyBindings(viewModel); </script>
若是咱们使用value binding的参数是一个observable,那么KO会设定一个双向的绑定,即form元素会与view model property互相影响;
若是参数是一个通常的view model property(不是observable),则KO会设定一个单项的绑定,即每当用户修改form元素的value时,KO便会修改相应的view model property,反之则不会对form元素形成影响;
若是参数并非一个简单的property,而是一个函数或是比较判断语句,则KO只会利用这一语句返回的值来初始化form元素的value,以后并不会在二者之间创建联系。
<!-- 双向绑定。文本框填充;同步两种方式。 --> <p>First value: <input data-bind="value: firstValue" /></p> <!-- 单向绑定。文本框填充;仅从文本框来同步模型。 --> <p>Second value: <input data-bind="value: secondValue" /></p> <!-- 没有绑定。文本框填充,但不该对任何变化。 --> <p>Third value: <input data-bind="value: secondValue.length > 8" /></p> <script type="text/javascript"> var viewModel = { firstValue: ko.observable("hello"), // Observable secondValue: "hello, again" // Not observable }; ko.applyBindings(viewModel); </script>
这个例子仅仅显示一个消息 , 若是当前具备焦点的文本框 , 而且使用按钮来代表你能够触发焦点。
<input data-bind="hasFocus: isSelected" /> <button data-bind="click: setIsSelected">Focus programmatically</button> <span data-bind="visible: isSelected">The textbox has focus</span> <script> var viewModel = { isSelected: ko.observable(false), setIsSelected: function() { this.isSelected(true); } }; ko.applyBindings(viewModel); </script>
这是切换 "编辑" 模式的一种方便方法。
在本例中, ui 要显示<span>
或者<input>
的元素, 取决于模型的编辑属性。
非聚焦的<input>
元素将editing
设置为 false
, ui 退出 "编辑" 模式。
<p> Name: <b data-bind="visible: !editing(), text: name, click: edit"> </b> <input data-bind="visible: editing, value: name, hasFocus: editing" /> </p> <p><em>Click the name to edit it; click elsewhere to apply changes.</em></p> <script> function PersonViewModel(name) { // Data this.name = ko.observable(name); this.editing = ko.observable(false); // Behaviors this.edit = function() { this.editing(true) } } ko.applyBindings(new PersonViewModel("Bert Bertington")); </script>
visible: !editing()
表示触发click时,执行 edting 的非方法。
checked绑定是关联到checkable的form表单控件到view model上 - 例如checkbox(<input type='checkbox'>
)或者radio button(<input type='radio'>
) 。当用户check关联的form表单控件的时候,view model对应的值也会自动更新,相反,若是view model的值改变了,那控件元素的check/uncheck状态也会跟着改变。
注:对text box,drop-down list和全部non-checkable的form表单控件,用value绑定来读取和写入是该元素的值,而不是checked绑定。
<p>Send me spam:<input type="checkbox" data-bind="checked:wantsSpam" /></p> <script type="text/javascript"> var viewModel = { wantsSpam: ko.observable(true) }; viewModel.wantsSpam(false); ko.applyBindings(viewModel); </script>
<p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p> <div data-bind="visible: wantsSpam"> Preferred flavors of spam: <div><input type="checkbox" value="cherry" data-bind="checked: spamFlavors" /> Cherry</div> <div><input type="checkbox" value="almond" data-bind="checked: spamFlavors" /> Almond</div> <div><input type="checkbox" value="msg" data-bind="checked: spamFlavors" /> Monosodium Glutamate</div> </div> <script type="text/javascript"> var viewModel = { wantsSpam: ko.observable(true), spamFlavors: ko.observableArray(["cherry","almond"]) // Initially checks the Cherry and Almond checkboxes }; ko.applyBindings(viewModel); // ... then later ... viewModel.wantsSpam(false); viewModel.spamFlavors.push("msg"); // Now additionally checks the Monosodium Glutamate checkbox </script>
<p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p> <div data-bind="visible: wantsSpam"> Preferred flavor of spam: <div><input type="radio" name="flavorGroup" value="cherry" data-bind="checked: spamFlavor" /> Cherry</div> <div><input type="radio" name="flavorGroup" value="almond" data-bind="checked: spamFlavor" /> Almond</div> <div><input type="radio" name="flavorGroup" value="msg" data-bind="checked: spamFlavor" /> Monosodium Glutamate</div> </div> <script type="text/javascript"> var viewModel = { wantsSpam: ko.observable(true), spamFlavor: ko.observable("almond") // Initially selects only the Almond radio button }; // ... then later ... viewModel.spamFlavor("msg"); // Now only Monosodium Glutamate is checked ko.applyBindings(viewModel); </script>
对于radio buttons,KO只有当参数值等于radio button value属性值的时候才设置元素为checked状态。因此参数应是字符串。在上面的例子里只有当view model 的spamFlavor 属性等于“almond”的时候,该radio button才会设置为checked。
固然,最有用的是设置一组radio button元素对应到一个单个的view model 属性。确保一次只能选择一个radio button须要将他们的name属性名都设置成同样的值(例如上个例子的flavorGroup值)。这样的话,一次就只能选择一个了。
若是参数是监控属性observable的,那元素的checked状态将根据参数值的变化而更新,若是不是,那元素的value值将只设置一次而且之后不在更新。
若是你还包括结合 checkedValue
这个定义的值 , 使用checked替代value属性。若是但愿该值不是字符串 (如整数或对象), 或者但愿动态设置值, 则此功能很是有用。
在如下示例中 , 对象自己 (其不是项目 itemName
将被包括在字符串中) chosenItems
当阵列相对应的复选框被检查 :
<!-- ko foreach: items --> <input type="checkbox" data-bind="checkedValue: $data, checked: $root.chosenItems" /> <span data-bind="text: itemName"></span> <!-- /ko --> <script type="text/javascript"> var viewModel = { items: ko.observableArray([ { itemName: "Choice 1" }, { itemName: "Choice 2" } ]), chosenItems: ko.observableArray() }; ko.applyBindings(viewModel); </script>
若是选中 value 参数是一个可观察值, 则每当值发生更改且当前检查元素时, 绑定都将更新选中的模型属性。对于复选框, 它将从数组中删除旧值并添加新值。对于单选按钮, 它将只更新模型值。
options绑定控制什么样的options在drop-down列表里(例如:<select>
)或者 multi-select 列表里 (例如:<select size='6'>
)显示。此绑定不能用于<select>
以外的元素。关联的数据应是数组(或者是observable数组),<select>
会遍历显示数组里的全部的项。
对于multi-select
列表,设置或者获取选择的多项须要使用selectedOptions
绑定。
对于single-select
列表,你也可使用value绑定读取或者设置元素的selected
项。
<p>Destination country: <select data-bind="options: availableCountries"></select></p> <script type="text/javascript"> var viewModel = { availableCountries: ko.observableArray(['France', 'Germany', 'Spain']) }; ko.applyBindings(viewModel); viewModel.availableCountries.push('China'); </script>
该参数是一个数组(或者observable数组)。对每一个item,KO都会将它做为一个<option>
添加到<select>
里,以前的options都将被删除。
若是参数是一个string数组,那你不须要再声明任何其它参数。<select>
元素会将每一个string显示为一个option。不过,若是你让用户选择的是一个JavaScript对象数组(不只仅是string),那就须要设置optionsText
和optionsValue
这两个参数了。
若是参数是监控属性observable的,那元素的options项将根据参数值的变化而更新,若是不是,那元素的value值将只设置一次而且之后不在更新。
若是对上面的select UI元素加上multiple="true"
<p> Choose some countries you would like to visit: <select data-bind="options: availableCountries" size="5" multiple="true"></select> </p>
<p> Your country: <select data-bind="options: availableCountries, optionsText: 'countryName', value: selectedCountry, optionsCaption: 'Choose...'"></select> </p> <div data-bind="visible: selectedCountry"> <!-- Appears when you select something --> You have chosen a country with population <span data-bind="text: selectedCountry() ? selectedCountry().countryPopulation : 'unknown'"></span>. </div> <script type="text/javascript"> // Constructor for an object with two properties var Country = function (name, population) { this.countryName = name; this.countryPopulation = population; }; var viewModel = { availableCountries: ko.observableArray([ new Country("UK", 65000000), new Country("USA", 320000000), new Country("Sweden", 29000000) ]), selectedCountry: ko.observable() // Nothing selected by default }; ko.applyBindings(viewModel); </script>
有时候,默认状况下不想选择任何option项。可是single-select drop-down列表因为每次都要默认选择以项目,怎么避免这个问题呢?经常使用的方案是加一个“请选择的”或者“Select an item”的提示语,或者其它相似的,而后让这个项做为默认选项。
咱们使用optionsCaption参数就能很容易实现,它的值是字符串型,做为默认项显示。例如:
<select data-bind='options: myOptions, optionsCaption: "Select an item...", value: myChosenValue'></select>
KO会在全部选项上加上这一个项,而且设置value值为undefined。因此,若是myChosenValue被设置为undefined(默认是observable的),那么上述的第一个项就会被选中
<!-- Same as example 3, except the <select> box expressed as follows: --> <select data-bind="options: availableCountries, optionsText: function(item) { return item.countryName + ' (pop: ' + item.countryPopulation + ')' }, value: selectedCountry, optionsCaption: 'Choose...'"></select>
optionsText
上面《Drop-down list展现的任意JavaScript对象,不只仅是字符串》中展现的绑定JavaScript对象到option上 – 不只仅是字符串。这时候你须要设置这个对象的那个属性做为drop-down列表或multi-select列表的text来显示。设置额外的参数optionsText将对象的属性名countryName做为显示的文本。
若是不想仅仅显示对象的属性值做为每一个item项的text值,那你能够设置optionsText 为JavaScript 函数,而后再函数里经过本身的逻辑返回相应的值(该函数参数为item项自己)。
optionsValue
和optionsText相似, 你也能够经过额外参数optionsValue来声明对象的那个属性值做为该<option>
的value值。
经典场景:如在更新options的时候想保留原来的已经选择的项。例如,当你重复屡次调用Ajax获取car列表的时候,你要确保已经选择的某个car一直都是被选择上,那你就须要设置optionsValue为“carId”或者其它的unique标示符,不然的话KO找不知道以前选择的car是新options里的哪一项
selectedOptions
对于multi-select列表,你能够用selectedOptions读取和设置多个选择项。技术上看它是一个单独的绑定,有本身的文档,请参考: selectedOptions绑定。
optionsCaption
有时, 默认状况下, 您可能不但愿选择任何特定选项。可是, 单选下拉列表一般从选定的某个项目开始, 那么如何避免预先选择的内容呢?一般的解决方案是在选项列表中加上一个特殊的虚拟选项, 该选项只读 "选择一个项目" 或 "请选择一个选项" 或相似的选项, 默认状况下选择该选项。
optionsIncludeDestroyed
有时您可能但愿阵列条目标记为已删除 , 但实际上没有失去记载。这已知为非破坏性的删除。对于细节 , 请参见在功能上破坏observableArray。
经过缺省 , 该选项将忽略绑定 (即 , 把阵列条目被标记为 “已损坏” 。若是你想破坏显示条目 , 而后指定该附加参数 :
<select data-bind='options: myOptions, optionsIncludeDestroyed: true'></select>
optionsAfterRender
若是须要在生成的选项元素上运行一些进一步的自定义逻辑, 则可使用选项售后渲染回调。
valueAllowUnset
若是您但愿 knockout 容许您的模型属性获取在您的<select>
元素 (并经过使<select>
元素空白),请看文档Using valueAllowUnset with select elements
selectedOptions绑定用于控制multi-select列表已经被选择的元素,用在使用options绑定的<select>
元素上。
当用户在multi-select列表选择或反选一个项的时候,会将view model的数组进行相应的添加或者删除。一样,若是view model上的这个数组是observable数组的话,你添加或者删除任何item(经过push或者splice)的时候,相应的UI界面里的option项也会被选择上或者反选。这种方式是2-way绑定。
注:控制single-select下拉菜单选择项,你可使用value绑定。
<p> Choose some countries you'd like to visit: <select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select> </p> <script type="text/javascript"> var viewModel = { availableCountries: ko.observableArray(['France', 'Germany', 'Spain']), chosenCountries: ko.observableArray(['Germany']) // Initially, only Germany is selected }; // ... then later ... viewModel.chosenCountries.push('France'); // Now France is selected too ko.applyBindings(viewModel); </script>
该参数是数组(或observable数组)。KO设置元素的已选项为和数组里match的项,以前的已选择项将被覆盖。
若是参数是依赖监控属性observable数组,那元素的已选择项selected options项将根据参数值的变化(经过push,pop,或其它observable数组方法)而更新,若是不是,那元素的已选择项selected options将只设置一次而且之后不在更新。
无论该参数是否是observable数组,用户在multi-select列表里选择或者反选的时候,KO都会探测到,而且更新数组里的对象以达到同步的结果。这样你就能够获取options已选项。
支持让用户选择任意JavaScript对象
在上面的例子里,用户能够选择数组里的字符串值,可是选择不限于字符串,若是你愿意你能够声明包含任意JavaScript对象的数组,查看options绑定如何显示JavaScript对象到列表里。
这种场景,你能够用selectedOptions来读取或设置这些对象自己,而不是页面上显示的option表示形式,这样作在大部分状况下都很是清晰。view model就能够探测到你从数组对象里选择的项了,而没必要关注每一个项和页面上展现的option项是如何map的。
1.在使用KO的时候,一些技术可能依赖于某些元素的name属性,尽管他们没有什么意义。例如,jQuery Validation验证当前只验证有name属性的元素。为配合Knockout UI使用,有些时候须要使用uniqueName绑定避免让jQuery Validation验证出错。
2.IE 6下,若是radio button没有name属性是不容许被checked了。大部分时候都没问题,由于大部分时候radio button元素都会有name属性的做为一组互相的group。不过,若是你没声明,KO内部会在这些元素上使用uniqueName那么以确保他们能够被checked。
例如:
<input data-bind="value: someModelProperty, uniqueName: true" />
就像上面的例子同样,传入true(或者能够转成true的值)以启用uniqueName绑定。