Knockoutjs属性绑定(Bindings)之表单处理(Working with form fields)
我们在使用Knockoutjs最多的时候莫过于使用上次介绍的流程控制(Control flow)和今天将要介绍的表单处理(Working with form fields)了,我们使用表单处理可以帮助我们处理比如事件、验证等功能,下面我们就开始吧。
一、click binding
使用click binding可以对某一个可见的DOM元素进行事件绑定,当用户点击这个元素时会执行对应的方法,完成相应的功能,我们经常在button、input、a等DOM元素上进行click binding。
(1)、下面我们来看一个例子:每当我点击Button之后,点击次数都会加1
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <div> 4 You've clicked <span data-bind="text: numberOfClicks"></span> times 5 <button data-bind="click: incrementClickCounter">Click me</button> 6 </div> 7 8 <script type="text/javascript"> 9 var viewModel = { 10 numberOfClicks: ko.observable(0), 11 incrementClickCounter: function () { 12 var previousCount = this.numberOfClicks(); 13 this.numberOfClicks(previousCount + 1); 14 } 15 }; 16 ko.applyBindings(viewModel); 17 </script>
(2)、我们也可以把当前元素作为参数传递给所要调用的方法,如下例子:我们点击按钮,然后删除按钮对应的元素
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <ul data-bind="foreach: places"> 4 <li> 5 <span data-bind="text: $data"></span> 6 <button data-bind="click: $parent.removePlace">Remove</button> 7 </li> 8 </ul> 9 10 <script type="text/javascript"> 11 function MyViewModel() { 12 var self = this; 13 self.places = ko.observableArray(['London', 'Paris', 'Tokyo']); 14 15 // The current item will be passed as the first parameter, so we know which place to remove 16 self.removePlace = function (place) { 17 self.places.remove(place) 18 } 19 } 20 ko.applyBindings(new MyViewModel()); 21 </script>
关于这个例子我们有以下的两点说明:
(a)、如果我们在一个嵌套的元素中使用click binding的话,例如我们在foreach或者with块中使用click binding,但是此时click对应的方法在View Model的根部或者他的父上下文,此时我们需要一个前缀比如$parent或者$root来定位我们的方法。
(b)、在我们的View Model中我们经常为我们的this起一个别名为self,这样就会防止this指向的地方改变而导致我们程序的错误。
(3)、定义事件对象和传递更多的参数
(a)、定义一个事件
1 <button data-bind="click: myFunction"> 2 Click me 3 </button> 4 5 <script type="text/javascript"> 6 var viewModel = { 7 myFunction: function(data, event) { 8 if (event.shiftKey) { 9 //do something different when user has shift key down 10 } else { 11 //do normal action 12 } 13 } 14 }; 15 ko.applyBindings(viewModel); 16 </script>
此时就会判断,如果是shift 键点击的话,则会执行对应的内容,否则执行其他的内容。
(b)、传递更多的参数
如果我们想要传递很多参数给调用的方法的话,我们可以在标签中包括对应方法要传递的参数等,如下:
1 <button data-bind="click: function(data, event) { myFunction('param1', 'param2', data, event) }"> 2 Click me 3 </button>
但是,如果我们不想要在标签中出现这么多的内容的话,我们可以使用KO的bind方法来进行方法的传递,如下:
1 <button data-bind="click: myFunction.bind($data, 'param1', 'param2')"> 2 Click me 3 </button>
(4)、防止事件的冲突
在默认情况下,Knockoutjs允许事件绑定从一个元素传递到更高一级的元素。比如:一个DOM元素和他的父元素都使用了click事件,如果我们点击其中一个则两个事件都会执行,此时,我们就可以使用“clickBubble
”来制定哪个事件不执行,如下:
1 <div data-bind="click: myDivHandler"> 2 <button data-bind="click: myButtonHandler, clickBubble: false"> 3 Click me 4 </button> 5 </div>
在默认的情况下,当点击事件时会首先执行myButtonHandler,然后执行myDivHandler。但是当我们在button上使用的clickBubble:false时,则会跳过myButtonHandler去执行myDivHandler了。
二、event binding
我们也可以使用event binding来进行事件绑定,比如:keypress
, mouseover
、 mouseout等
(1)、使用mouseover和mouseout控制是否显示div
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <div> 4 <div data-bind="event: { mouseover: enableDetails, mouseout: disableDetails }"> 5 Mouse over me 6 </div> 7 <div data-bind="visible: detailsEnabled"> 8 Details 9 </div> 10 </div> 11 12 <script type="text/javascript"> 13 var viewModel = { 14 detailsEnabled: ko.observable(false), 15 enableDetails: function () { 16 this.detailsEnabled(true); 17 }, 18 disableDetails: function () { 19 this.detailsEnabled(false); 20 } 21 }; 22 ko.applyBindings(viewModel); 23 </script>
(2)、参数传递
当使用event binding的时候,Knockoutjs会默认将当前的Model Value作为第一个参数传递给事件方法。如下:
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <ul data-bind="foreach: places"> 4 <li data-bind="text: $data, event: { mouseover: $parent.logMouseOver }"> </li> 5 </ul> 6 <p>You seem to be interested in: <span data-bind="text: lastInterest"> </span></p> 7 8 <script type="text/javascript"> 9 function MyViewModel() { 10 var self = this; 11 self.lastInterest = ko.observable(); 12 self.places = ko.observableArray(['London', 'Paris', 'Tokyo']); 13 14 // The current item will be passed as the first parameter, so we know which place was hovered over 15 self.logMouseOver = function (place) { 16 self.lastInterest(place); 17 } 18 } 19 ko.applyBindings(new MyViewModel()); 20 </script>
(3)、传递多个参数
在进行多个参数传递时,我们可以参照click binding中的多个参数传递,如下:
1 <div data-bind="event: { mouseover: function(data, event) { myFunction('param1', 'param2', data, event) } }"> 2 Mouse over me 3 </div>
我们也可以使用下面的方法进行多个参数的传递:
1 <button data-bind="event: { mouseover: myFunction.bind($data, 'param1', 'param2') }"> 2 Click me 3 </button>
(4)、同样的在event binding中也会有事件的冲突,在click binding中我们使用clickBubble
来处理,如果我们要mouseover事件的话我们可以使用
mouseoverBubble
来处理,如果使用mouseout的话我们可以使用
mouseoutBubble来处理等等。
三、submit binding
我们可以使用submit binding进行表单的提交,但我们要注意此时并没有将表单提交给服务器,而是提交给了我们的View Model。使用submit binding的示例如下:
1 <form data-bind="submit: doSomething"> 2 ... form contents go here ... 3 <button type="submit">Submit</button> 4 </div> 5 6 <script type="text/javascript"> 7 var viewModel = { 8 doSomething : function(formElement) { 9 // ... now do something 10 } 11 }; 12 </script>
四、enable binding
使用enable binding可以很好的控制DOM元素是否显示等(当enable的值为true时),这对input
, select
, textarea等特别的有用。下面我们来看一个例子:我们定义一个checkbox和一个text,当用户勾选checkbox以后才能在text中输入内容,否则不能输入:
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p> 4 <input type='checkbox' data-bind="checked: hasCellphone" /> 5 I have a cellphone 6 </p> 7 <p> 8 Your cellphone number: 9 <input type='text' data-bind="value: cellphoneNumber, enable: hasCellphone" /> 10 </p> 11 12 <script type="text/javascript"> 13 var viewModel = { 14 hasCellphone: ko.observable(false), 15 cellphoneNumber: "" 16 }; 17 ko.applyBindings(viewModel); 18 </script>
五、disable binding
disable binding的使用方法和enable binding的使用方法一样,只是判断条件相反。
六、value binding
我们可以使用value binding为DOM元素设置默认值,比如:我们使用value为其设置默认的用户名和密码
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p>Login name: <input data-bind="value: userName" /></p> 4 <p>Password: <input type="password" data-bind="value: userPassword" /></p> 5 6 <script type="text/javascript"> 7 var viewModel = { 8 userName: ko.observable("123456"), // Initially blank 9 userPassword: ko.observable("abc"), // Prepopulate 10 }; 11 ko.applyBindings(viewModel); 12 </script>
七、hasfocus binding
在使用hasfocus binding时,我们可以通过View Model层为一个元素设置true和false来控制hasfocus,也可以在View层对某一个元素进行绑定。
例1:当input获得焦点时则会显示相应的文本
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <input data-bind="hasfocus: isSelected" /> 4 <button data-bind="click: setIsSelected">Focus programmatically</button> 5 <span data-bind="visible: isSelected">The textbox has focus</span> 6 7 <script type="text/javascript"> 8 var viewModel = { 9 isSelected: ko.observable(false), 10 setIsSelected: function () { this.isSelected(true) } 11 }; 12 ko.applyBindings(viewModel); 13 </script>
例2:点击文本后即可进行编辑
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p> 4 Name: 5 <b data-bind="visible: !editing(), text: name, click: edit"> </b> 6 <input data-bind="visible: editing, value: name, hasfocus: editing" /> 7 </p> 8 <p><em>Click the name to edit it; click elsewhere to apply changes.</em></p> 9 10 <script type="text/javascript"> 11 function PersonViewModel(name) { 12 // Data 13 this.name = ko.observable(name); 14 this.editing = ko.observable(false); 15 16 // Behaviors 17 this.edit = function () { this.editing(true) } 18 } 19 20 ko.applyBindings(new PersonViewModel("Bert Bertington")); 21 </script>
八、checked binding
(1)、checkbox使用
1 <p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p> 2 <div data-bind="visible: wantsSpam"> 3 Preferred flavors of spam: 4 <div><input type="checkbox" value="cherry" data-bind="checked: spamFlavors" /> Cherry</div> 5 <div><input type="checkbox" value="almond" data-bind="checked: spamFlavors" /> Almond</div> 6 <div><input type="checkbox" value="msg" data-bind="checked: spamFlavors" /> Monosodium Glutamate</div> 7 </div> 8 9 <script type="text/javascript"> 10 var viewModel = { 11 wantsSpam: ko.observable(true), 12 spamFlavors: ko.observableArray(["cherry","almond"]) // Initially checks the Cherry and Almond checkboxes 13 }; 14 15 // ... then later ... 16 viewModel.spamFlavors.push("msg"); // Now additionally checks the Monosodium Glutamate checkbox 17 </script>
(2)、radio使用
1 <p>Send me spam: <input type="checkbox" data-bind="checked: wantsSpam" /></p> 2 <div data-bind="visible: wantsSpam"> 3 Preferred flavor of spam: 4 <div><input type="radio" name="flavorGroup" value="cherry" data-bind="checked: spamFlavor" /> Cherry</div> 5 <div><input type="radio" name="flavorGroup" value="almond" data-bind="checked: spamFlavor" /> Almond</div> 6 <div><input type="radio" name="flavorGroup" value="msg" data-bind="checked: spamFlavor" /> Monosodium Glutamate</div> 7 </div> 8 9 <script type="text/javascript"> 10 var viewModel = { 11 wantsSpam: ko.observable(true), 12 spamFlavor: ko.observable("almond") // Initially selects only the Almond radio button 13 }; 14 15 // ... then later ... 16 viewModel.spamFlavor("msg"); // Now only Monosodium Glutamate is checked 17 </script>
九、options binding
使用options binding可以实现我们的下拉列表框,下面我们看几个例子:
(1)、一个简单的下拉列表
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p>Destination country: <select data-bind="options: availableCountries"></select></p> 4 5 <script type="text/javascript"> 6 var viewModel = { 7 availableCountries: ko.observableArray(['France', 'Germany', 'Spain']) // These are the initial options 8 }; 9 10 // ... then later ... 11 viewModel.availableCountries.push('China'); // Adds another option 12 ko.applyBindings(viewModel); 13 </script>
(2)、多选列表框
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p>Destination country: <select data-bind="options: availableCountries" size="5" multiple="true"></select></p> 4 5 <script type="text/javascript"> 6 var viewModel = { 7 availableCountries: ko.observableArray(['France', 'Germany', 'Spain']) // These are the initial options 8 }; 9 10 // ... then later ... 11 viewModel.availableCountries.push('China'); // Adds another option 12 ko.applyBindings(viewModel); 13 </script>
(3)、使用JavaScript对象来作为下拉列表的内容
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p> 4 Your country: 5 <select data-bind="options: availableCountries, optionsText: 'countryName', value: selectedCountry, optionsCaption: 'Choose...'"></select> 6 </p> 7 8 <div data-bind="visible: selectedCountry"> <!-- Appears when you select something --> 9 You have chosen a country with population 10 <span data-bind="text: selectedCountry() ? selectedCountry().countryPopulation : 'unknown'"></span>. 11 </div> 12 13 <script type="text/javascript"> 14 // Constructor for an object with two properties 15 var Country = function (name, population) { 16 this.countryName = name; 17 this.countryPopulation = population; 18 }; 19 20 var viewModel = { 21 availableCountries: ko.observableArray([ 22 new Country("UK", 65000000), 23 new Country("USA", 320000000), 24 new Country("Sweden", 29000000) 25 ]), 26 selectedCountry: ko.observable() // Nothing selected by default 27 }; 28 ko.applyBindings(viewModel); 29 </script>
十、selectedOptions binding
实现多选列表框的默认选中,例:
1 <script type="text/javascript" src="knockout-2.2.0.js"></script> 2 3 <p> 4 Choose some countries you'd like to visit: 5 <select data-bind="options: availableCountries, selectedOptions: chosenCountries" size="5" multiple="true"></select> 6 </p> 7 8 <script type="text/javascript"> 9 var viewModel = { 10 availableCountries: ko.observableArray(['France', 'Germany', 'Spain']), 11 chosenCountries: ko.observableArray(['Germany']) // Initially, only Germany is selected 12 }; 13 14 // ... then later ... 15 viewModel.chosenCountries.push('France'); // Now France is selected too 16 ko.applyBindings(viewModel); 17 </script>