<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綁定。