Knockout是一个JavaScript库,可帮助您使用干净的底层数据模型创建丰富的响应式显示和编辑器用户界面。只要您有动态更新的UI部分(例如,根据用户的操作或外部数据源更改而更改),KO可以帮助您更简单,更可维护地实施。
参考Knockout官方文档:https://knockoutjs.com/documentation/introduction.html
Knockout围绕三个核心功能创建:
可观察量和依赖性跟踪声明性绑定模板MVVM模式和视图模型
模型--视图模型--视图(MVVM)是用于构建用户界面的设计模式,可以用三部分来划分复杂的UI。
模型:应用程序存储的数据。此数据表示的是业务域中的对象和操作。使用KO时,通常会对某些服务器端代码进行AJAX调用,以读取和写入此存储的模型数据。视图模型:在UI上的数据和操作的纯码表示,但它不是UI本身,他没有按钮和显示样式的概念,也不是持久的数据模型,它保存的是用户正在使用的未保存数据。使用KO时,您的视图模型是纯JavaScript对象,不是HTML。视图:表示视图模型的状态可见,互动的用户界面。使用KO时,您的视图只是声明性的绑定的HTML文档,以将其连接到视图模型。(显示来自数据模型的信息,将命令(例如点击)发送到视图模型,并在视图模型的状态发生变化时进行更新)1.要使用KO创建视图模型,只需声明任何JavaScript对象(声明)
var myViewModel={ personName='Bob'; personAge:123; }2.使用声明性绑定创建此视图模型的非常简单的视图(绑定)
The name is <span data-bind="text:personName"></span>3.data-bind不是HTML的,由于浏览器不知道它的含义,所以需要激活Knockout才能使其生效。
激活有两种方式:
第一种,全部激活,ko.applyBindings(myViewModel);第一个参数说明要使用的视图模型对象与它激活的声明性绑定
第二种,指定部分激活,ko.applyBindings(myViewModel, document.getElementById('someElementId'));
您可以传递第二个参数来定义要搜索data-bind属性的文档的哪个部分。例如,ko.applyBindings(myViewModel, document.getElementById('someElementId'))。这someElementId会将激活限制为具有ID 及其后代的元素,如果您希望拥有多个视图模型并将每个视图模型与页面的不同区域相关联,这将非常有用。
ko一个最主要的优点就是它可以在视图模型更改时自动更新UI.
此时需要将视图模型更改为可观察对象,是特殊的JavaScript对象,可以自动检查依赖关系。
var myViewModel={ //重写前面的视图模型 personName:ko.observable("Bob"); personAge:ko.observable(123); }之前的data-bind将会继续工作,不同的是他现在能检测到变化,并能根据改变更新视图。
类如‘Mary’通过调用更改名称值时myViewModel.personName('Mary'),text绑定将自动更新关联DOM元素的文本内容,这就是自动更新。
4.监控属性数组(Observables Arrays)
常用的方法:
myObservableArray.push("new value"):增加一个新的元素myObservableArray.pop():删除一个元素,并返回其值myObservableArray.unshift("new value"):在数组的开始处增加一个新的元素myObservableArray.shift():删除数组的第一个元素,并返回其值myObservableArray.reverse():反转数组的顺序myObservableArray.sort():数组的排序 ,默认排序是按照字母,数字顺序进行排序myObservableArray.splice():数组截取。例如:myObservableArray.splice(1, 3),代表从数组的第一个元素开始,截取三个元素,并且将他们作为数组返回。remove和removeAll
myObservableAraay.remove(item) 移除myObservableArray数组内所有匹配item的对象,并把所有对象组成一个数返回
myObservableAraay.remove(function(item) {return item.age<18}) 移除myObservableArray数组内年龄属性小于18,并把所有对象组成一个数返回
myObservableAraay.removeAll(['Chad', 132, undefined]) 移除myObservableArray数组内所有匹配'Chad',123, orundefined 的对象并把它们组成新数组返回
myObservableArray.removeAll()移除myObservableArray数组内所有数据,并返回这些数据组成的一个新数组
绑定:控制文字和外观
1.visible绑定
与visible结合根据你传的值来决定与之绑定的DOM元素隐藏还是可见。
例子:
<div data-bind="visible:shouldShowMessage"> You will see this message when "shouldShowMessage" is true. </div> <script type="text/javascript"> var viewModel={ shouldShowMessage:ko.observable(true) } viewModel.shouldShowMessage(false) //此时绑定的这个层是隐藏的 viewModel.shouldShowMessage(true) //他此时是可见的 </script>参数:类似于false的值(false,0,null,undefined),DOM元素为隐藏。此优先于你使用CSS定义的任何显示样式。
类似于true值(例如,true,非null对象或数组)使其变为可见。
还可以使用函数和表达式来控制元素可见性
可以使用js函数和其表达式作为参数值,此时,KO将会运行函数,评估表达式来使用结果来确定是否隐藏元素。
<div data-bind="visible:myValues().length>0"> You will see this message only when 'myValues' has at least one member. </div> <script type="text/javascript"> var viewModel={ myValues:ko.observableArray([]) //此时为空,表达式false,隐藏 }; viewModel.myValues.push("some value"); //此时可见 </script>2.与text结合
与text相结合的DOM元素,显示参数的文本值。(一般在<span>与<em>(斜体)中使用,但在技术上可以在任意元素上使用)
例子:
this message is:<span data-bind="text:myMessage"></span> <script type="text/javascript"> var viewModel={ myMessage:ko.observable() }; viewModel.myMessage("Hello"); </script>主要参数:
knockout会将文本值覆盖为参数值,如果提供的不是数字,字符串的话(对象,数组),则会将参数使用toString()方法。
使用表达式来确定文本值
the gold is <span data-bind="text:price()>50 ? 'expensive': 'cheap'"></span> <script type="text/javascript"> var viewModel={ price:ko.observable(24) }; </script>3.与html组合
与HTML结合的相关DOM元素,显示html绑定的参数的html格式。
<div data-bind="html:detail"></div> <script type="text/javascript"> var viewModel={ detail:ko.observable() } viewModel.detail("<em>i love you<a href="report.html"></a></em>") </script>主要参数:ko会清除以前的内容,然后在显示html的参数值,如果提供的不是数字或字符串,那innerHTM将相当于.toString()
注意:因为此绑定使用设置元素的内容innerHTML,不要与不受信任的模型值一起使用,因为这可能会导致脚本注入攻击的可能。
4.与attr的组合
提供一种通用的方法来设置相关联的DOM元素的任何属性的值。譬如可以设置title元素的属性,href的值等等,当属性值被更新时自动对应的模型属性更改。
例如:
<a data-bind="attr:{href:url;title:detail}"> report </a> <script type="text/javascript"> var viewModel={ url:ko.observable("1.html"), detail:ko.observable("i love you") }; </script>此时herf和title的属性值已经设置完毕。
主要参数:应该传递的是JavaScript对象,其中属性名称要对应,属性值也要是相对应的属性值。
注意:当属性名不合法的时候,比如说a标签中的data-something不是合法的,解决办法就是用“ ”包装,使其变为字符串文字,字符串文字再JavaScript中是合法的。
绑定:控制流
1.与foreach绑定
使用此功能我们可以方便的循环遍历输出数组,集合中的内容。
例:(1)循环遍历输出数组
<table> <thead> <tr><th>First name</th><th>Last name</th></tr> //表头部分 </thead> <tbody data-bind="foreach:people"> <tr> <td data-bind="text:firstName"></td> <td data-bind="text: lastName"></td> </tr> </tbody> </table> <script type="text/javascript"> ko.applyBindings({ people:[ { firstName: 'Bert', lastName: 'Bertington' }, { firstName: 'Charles', lastName: 'Charlesforth' }, { firstName: 'Denise', lastName: 'Dentiste' } ] }); </script>(2)输出数组中的所有元素,可以使用$data来进行输出
<ul data-bind="foreach:people"> <li> my name is <b data-bind="text:$data"></b> </li> </ul> <script type="text/javascript"> ko.applyBindings({'jack','jane','kangkang'}); </script>当然,我们也可以使用$data来调用数组中的具体元素,比如可以使用$data.firstName来输出具体的值。
(3).使用$index,$parent等上下文属性
$index会随着数组的下标动态变化,当数组的长度-1时,$index也会随之减少。
$parent是使用foreach循环之外的元素的。
<h1 data-bind="text:name"></h1> <ul data-bind="foreach:people"> <li> <b data-bind="text:$data"></b> has a same name is <b data-bind="text:$parent.name"></b> </li> </ul>$parent可以调用循环体外的name属性。
(4).用“as”来为foreach中的元素起别名
我们可以使用$data来代替数组的元素,也可以使用as来为遍历的元素起一个别名。
<ul data-bind="foreach:{data:categories,as:'category'}"> <li> <ul data-bind="foreach:{data:items,as:'item'}"> <li> <span data-bind="text: category.name"></span>: //用别名调用它的属性值 <span data-bind="text: item"></span> </li> </ul> </li> </ul> <script type="text/javascript"> var viewModel={ categories:ko.observableArray([ { name: 'Fruit', items: ['Apple', 'Orange', 'Banana'] }, { name: 'Vegetables', items: ['Celery', 'Corn', 'Spinach'] } ]) }; ko.applyBindings(viewModel); </script>在使用别名的时候,注意是as:'category'而不是as:category.
5.在没有绑定属性的情况下使用foreach
不如说我只想循环输出代码中的<li></li>标签的话,我们就没有一个可绑定的元素。
<!-ko foreach:myItems-> <li><span data-bind="text:$data"></span></li> <!-/ko-> <script type="text/javascript"> ko.applyBindings({ myItems:['a','b','c'] }); </script>我们使用<!-ko foreach:xx-> <!-/ko->来表示循环的开始与结束,虽然这是个虚拟标签,但是与绑定在真实标签上一样的效果。
2.与if绑定
DOM元素与if绑定后,可以控制该组件的动态显示,有点类似于我们之前接触的visible属性,此属性一经绑定就不能更改了。
<label> <input type="checkbox" data-bind="checked:displayshow"> displayshow message </label> <div data-bind="if:displayshow"> are you see me </div> <script type="text/javascript"> ko.applyBindings({ diaplayshow:ko.observable(false) }); </script>这个例子是根据checkbox是否被选中来确定是否显示div中的内容。初始值是false的话,checkbox未被选中,div也显示不出来,当用户选中之后,displayshow的值就会变为true,此时div可以正常显示。
if绑定与visible绑定类似,都可以控制一段内容是否可以出现在页面里,不过前者可以真正控制HTML标签是否可以出现在DOM中,出于性能考虑,这种情况应该使用visible binding.
3.with绑定
我们可以使用with binding来重新定义一个上下文绑定。
<p data-bind="with: coords"> Latitude: <span data-bind="text: latitude"> </span> , Longitude: <span data-bind="text: longitude"> </span> </p> ko.applyBindings({ city: "London", coords: { latitude: 51.5001524, longitude: -0.1262362 } });我们用with:coords来指定coords的上下文,当我们使用coords下的属性时就可以直接使用了,而不用再通过coords.属性名 来调用了。
4.click绑定
click绑定就是DOM元素被点击时,执行在ts中定义的方法,大部分是用在button,input,和连接a上的,理论上可以在任意元素上使用。
<div> You've clicked <span data-bind="text: numberOfClicks"> </span> times <button data-bind="click: incrementClickCounter"> Click me </button> </div> <script type="text/javascript"> var viewModel = { numberOfClicks: ko.observable(0), //初始化span显示的文本值 incrementClickCounter: function() { var previousCount = this.numberOfClicks(); //获取span绑定的元素的值 this.numberOfClicks(previousCount + 1); //更新点击次数,构造文本值 } }; </script>主要参数:
click点击事件所执行的函数。(任意的javascript函数)
5.event绑定
event绑定是在DOM元素上添加指定的触发条件,满足条件时执行定义的JavaScript函数。大部分用在keypress,mouseover,mouseout。
mouseover事件,就是当鼠标移到目标元素的上方时。
$("#xx").mouseover(function(){...}) //jquery选定id为xx的元素,出发mouseover事件。例,当鼠标在第一个元素上移入,移出时绑定的事件会相应的触发,从而控制第二个元素的显示与隐藏。
<div> <div data-bind="event:{mouseover:enableDetails,mouseout:disableDetails}"> mouse over me </div> <div data-bind="visible:Details"> i love you </div> </div> <script type="text/javascript"> var viewModel={ Details:ko.observable(false), enableDetails:function(){ this.Details(ture); }, disableDetails:function(){ this.Details(false); } </script>主要参数:
需要传入一个javascript对象,他的属性名是事件名称,它的值是需要执行的函数。
6.submit绑定
在form表单上添加指定的事件以便该表单被提交时执行定义的javascript函数,当你使用submit时,knockout会阻止默认的form表单提交,而会执行你定义的绑定函数。
<form data-bind="submit: doSomething"> //绑定的自定义事件,submit只能用在form中 ... form contents go here ... <button type="submit"> Submit </button> </div> <script type="text/javascript"> var viewModel = { doSomething: function(formElement) { // ... now do something } }; </script>为什么不在submit上使用click绑定呢?
可以使用,但是submit可以handle其他提交的方式,比如在输入框中输入回车就可以提交表单。
主参数:
你绑定在submit上的自定义函数。
7.value绑定
当你编辑表单控件时,viewModel对应的属性值会发生变化;当viewModel对应的属性值发生变化时,表单控件中的内容也会更新。
例:
<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 }; </script>主要参数:
value:如果参数是监控属性observable的,那元素的value值将根据参数值的变化而更新。
其他参数:valueUpdate
此时KO使用的是自定义的事件而不是默认的离开焦点事件。
"change"(默认值):当失去焦点时更新viewModel的值,或者<select>的元素被选择
“keyup” – 当用户敲完一个字符以后立即更新view model。
“keypress” – 当用户正在敲一个字符但没有释放键盘的时候就立即更新view model。不像 keyup,这个更新和keydown是一样的。
“afterkeydown” – 当用户开始输入字符的时候就更新view model。主要是捕获浏览器的keydown事件或异步handle事件。
上述这些选项,如果你想让你的view model进行实时更新,使用“afterkeydown”是最好的选择。