JS组件系列——KnockoutJS⽤法
前⾔:出于某种原因,需要学习下Knockout.js,这个组件很早前听说过,但⼀直没尝试使⽤,这两天学习了下,觉得它真⼼不错,双向绑定的机制简直太爽了。今天打算结合bootstrapTable和Knockout去实现⼀个简单的增删改查,来体验⼀把神奇的MVVM。关于WebApi的剩余部分,博主⼀定抽时间补上。
⼀、Knockout.js简介
1、Knockout.js和MVVM
如今,各种前端框架应接不暇,令⼈眼花缭乱,有时不得不感叹作为程序猿也真是苦逼,总有学不完的技术,何时是尽头,除⾮你转化!苦海⽆边,回头是不是岸,由你决定!
Knockout.js是⼀个基于MVVM模式的轻量级的前端框架,有多轻?根据官⽹上⾯显⽰的最新版本v3.4.0,仅22kb。能够友好地处理数据模型和界⾯DOM的绑定,最重要的是,它的绑定是双向的,也就是说数据模型变化了,界⾯DOM上的数据也会跟着发⽣变化,反过来,界⾯DOM上的数据变化了,数据模型也会相应这个变化。这样能够⼤⼤减少我们的前端代码量,并且使得我们界⾯易于维护,再也不⽤写⼀⼤堆事件监控数据模型和界⾯DOM的变化了。下⾯博主会根据⼀个使⽤实例来说明这两点。
MVVM模式:这是⼀种创建⽤户界⾯的设计模式,MVVM把它拆分成三块就是Model、View、ViewMode
l,Model就是数据模型,View就是我们的视图,ViewModel就是⼀个视图模型,⽤来绑定数据模型和视图上⾯的dom元素。如果你使⽤过WPF和Silverlight,理解这个应该不是啥问题;没有使⽤过也什么关系,看完此⽂,你会有⼀个⼤致的认识。
2、最简单的实例
⼀般来说,如果你从零开始使⽤Knockout.js,你⾄少需要做以下四部
2.1、去官⽹下载knockout.js⽂件,然后引⽤到view页⾯⾥⾯。
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
注意:knockout.js并不需要jquery的⽀持,如果你的项⽬需要⽤到jquery的相关操作,则引⽤jquery;否则只引⽤以上⽂件即可。
2.2、定义ViewModel
viewmodel是什么?其实,在js⾥⾯,它看上去就像⼀个json对象。我们定义⼀个viewmodel:
var myViewModel = {
Name: "Lilei",
profession: "软件⼯程师",
};
2.3、view视图⾥⾯定义绑定data-bind的标签
<div>
姓名:<label data-bind="text:Name"></label><br />
职业:<input type="text" data-bind="textinput:Profession" />
</div>
注意:对应input标签的⽂本,需要使⽤textinput,⽽普通标签的⽂本使⽤text即可。
2.4、激活绑定
做了以上三步,还需要激活knockout的绑定
ko.applyBindings(myViewModel);
做到这四部,基本实现了⼀个最简单的viewmodel的数据绑定。得到效果:
如果你够细⼼,会发现ko.applyBindings()⽅法有两个参数,第⼀个就是我们需要绑定的viewmodel,第⼆个⼜是什么呢?
由 ko.applyBindings(myViewModel); 可知,第⼆个参数是⼀个可选参数,它表⽰viewmodel绑定的标签的作⽤域,⽐如,我们将以上代码改⼀下:
<div>
姓名:<label id="lb_name" data-bind="text:Name"></label><br />
职业:<input type="text" data-bind="textinput:Profession" />
</div>
ko.applyBindings(ElementById("lb_name"));
得到结果:
由此可知:第⼆个参数限定了myViewModel的作⽤范围,也就是说,只有在id="lb_name"的标签上⾯绑定才会⽣效,如果第⼆个参数是div 等容器标签,它表⽰该绑定的范围为该div下⾯的所有⼦标签。
3、监控属性
截⽌到上⾯的四步,我们看不到任何效果,看到的⽆⾮就是将⼀个json对象的的数据绑定到了html标签上⾯,这样做有什么意义呢?不是把简单的问题复杂化吗?别急,马上见证奇迹!上⽂说了,knockout最重要的意义在于双向绑定,那么如何实现我们的双向绑定呢?答案就是监控属性。
在knockout⾥⾯,核⼼的有三个监控属性:Obrvables,DependentObrvables,ObrvableArray,Obrve的意思翻译过来是观察、观测的意思,如果说成观察属性或者观测属性感觉不太恰当,我们暂且叫监控属性。
3.1、Obrvables:监控属性
我们将上⾯的例⼦改成这样:
<head>
<meta name="viewport" content="width=device-width" />
<title>Index3</title>
<script src="~/scripts/jquery-1.9.1.min.js"></script>
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
</head>
<body>
<div>
姓名:<label data-bind="text:Name"></label><br />
职业:<input type="text" data-bind="textinput:Profession" />
</div>
<div>学声乐的最佳年龄
<input type="text" id="txt_testobrvable" />
</div>
<script type="text/javascript">
//1.定义ViewModel
var myViewModel = {
Name: ko.obrvable("Lilei"),
Profession: "软件⼯程师",
};
//2.激活绑定
ko.applyBindings(myViewModel);
$(function () {
//注册⽂本框的textchange事件
$("#txt_testobrvable").on("input", function () {
myViewModel.Name($(this).val());
});
});
</script>
</body>
ko.obrvable("Lilei") 这⼀句的意义是将viewmodel的Name属性添加成为监控属性,⼀定Name属性变成监控属性,神奇的事情就发⽣了,我们来看看当我们写myViewModel.的时候:
Name由原来的属性变成⽅法了,也就是说⼀旦添加了ko.obrvable(),那么对应的属性就会变成⽅法,那么对于Name的取值和赋值都需要使⽤myViewModel.Name()来处理。我们先来看看效果:
代码释疑:很显然 myViewModel.Name($(this).val()); 这⼀句将当前⽂本框的值赋给了Name属性,由于界⾯绑定了Name属性,所以label ⾥⾯的值也随之发⽣了变化。或者你会说,这个使⽤textchang
e事件也可以做到的,只要将当前⽂本框的值赋给label标签,也可以达到这个效果,这个不算什么。确实,你的写法也可以达到⽬的,但是我们的监控属性的意义在于,任何地⽅改变了Name的值,界⾯都会随之变化,⽽不⽤每个地⽅去给label标签赋值,JS⾥⾯只需要把关注点⽅法myViewModel.Name()上⾯即可。是不是很厉害~~
3.2、DependentObrvables:监控依赖属性
如果看了上⾯的监控属性还没过瘾?下⾯再来看看监控依赖属性的使⽤。
我们将代码再改下看看:
<head>
<meta name="viewport" content="width=device-width" />
<title>Index3</title>
<script src="~/scripts/jquery-1.9.1.min.js"></script>
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
</head>
<body>
<div>
姓名:<input type="text" data-bind="textinput:Name" /><br />
职业:<input type="text" data-bind="textinput:Profession" /><br />
描述:<label data-bind="text:Des"></label>
</div>
<script type="text/javascript">
//1.定义ViewModel
var myViewModel = {
Name: ko.obrvable("Lilei"),
Profession: ko.obrvable("软件⼯程师"),
};
myViewModel.Des = ko.dependentObrvable(function () {
return "本⼈姓名——" + myViewModel.Name() + ",职业——" + myViewModel.Profession();
身份证过期了怎么补办});
//2.激活绑定
ko.applyBindings(myViewModel);</script>
</body>
先来看看效果:
代码释疑:通过添加监控依赖属性 ko.dependentObrvable() 将Des属性的值能同时监控到Name和Profession两个的变化,其中任何⼀个发⽣变化,Des绑定的标签都会触发改变,这样做的最⼤好处就是避免了我们js去操作dom的⿇烦,有点意思吧。
3.3、ObrvableArray;监控数组
除了上⾯两种,ko还⽀持对数组对象的监控。我们来看⼀个例⼦:
<head>
<meta name="viewport" content="width=device-width" />
<title>Index3</title>
<script src="~/scripts/jquery-1.9.1.min.js"></script>
<script src="~/scripts/knockout/knockout-3.4.0.min.js"></script>
</head>
<body>
<div><lect data-bind="options:deptArr,
optionsText:'Name'"></lect>
</div>
<div>
<input type="text" id="txt_testobrvable" /><input type="button" id="btn_test" value="新增部门" />
</div>
<script type="text/javascript">
var deptArr = ko.obrvableArray([
{ id: 1, Name: '研发部' },
{ id: 2, Name: '⾏政部' },
{ id: 3, Name: '⼈事部' }
]);
var viewModel = {
deptArr: deptArr,
};
ko.applyBindings(viewModel);
var i=4;
$(function () {
$("#btn_test").on("click", function () {
deptArr.push({ id: i++, Name: $("#txt_testobrvable").val() });
});
});
</script>
</body>
看看效果:
代码释疑:以上通过ko.obrvableArray()这个⽅法添加了对数组对象的监控,也就是说,js⾥⾯任何地⽅只要对deptArr数组对象做了数组的改变,都会触发UI给出相应。需要注意的⼀点是,监控数组实际上是监控的数组对象本⾝,对于数组对象⾥⾯的⼦对象属性发⽣变化,是⽆法监控到的。⽐如我们将点击事件改成这样:
$(function () {
$("#btn_test").on("click", function () {
deptArr[1].Name = "aaa";
});
});班会流程
效果:
由此说明数组监控实际上监控的是数组对象本⾝,对于数组⾥⾯元素的属性变化不会监控。如果确实
需要对数据⾥⾯对象的属性变化进⾏监控,需要再对数据⾥⾯对象属性使⽤ko.obrvable(),两者联合使⽤。有兴趣的可以试试。
4、ko⾥⾯常见的data-bind属性
上⽂中,我们使⽤了多个data-bind属性,那么在knockout⾥⾯,到底有多少个这种data-bind的属性呢。这⾥我们列出⼀些常⽤的属性。4.1、text和inputText
text,顾名思义就是⽂本的意思,这个绑定属性⼀般⽤于<label>、<span>、<div>等标签显⽰⽂本,当然,如果你愿意,任何标签都可以使⽤这个绑定。它是使⽤基本上没什么好说的。如果没有使⽤ko.obrvable(),则是静态绑定,否则是动态绑定。
inputText,input标签的⽂本,相当于input标签的value属性。
<div>
姓名:<label data-bind="text:Name"></label><br />
职业:<input type="text" data-bind="textinput:Profession" />
</div>
亲情
//1.定义ViewModel
var myViewModel = {
太空梦
Name: ko.obrvable("Lilei"),
Profession: "软件⼯程师",
};
//2.激活绑定
ko.applyBindings(myViewModel);
4.2、value春联七言
这个绑定属性⼀般⽤于input标签,和上⾯的inputText基本相似。只不过value更加规范。
和value⼀起使⽤的还有⼀个参数valueUpdate,它表⽰界⾯做⼀个什么操作的时候更新该value。valueUpdate主要取值有
change/keyup/keypress/afterkeydown等。分别表⽰⽂本变化、键盘缩起、键盘按下、键盘按下之后等操作时候更新value对应的viewmodel 的值。
姓名:<input type="text" data-bind="value:Name,valueUpdate:'keyup'" /><br />
var myViewModel = {
Name: ko.obrvable("Lilei"),
};//2.激活绑定
ko.applyBindings(myViewModel);
上述代码表⽰键盘收起的时候更新⽂本框的value属性和myViewModel的Name属性。
4.3、checked
checked绑定⼀般⽤于checkbox、radio等可以选中的表单元素,它对应的值是bool类型。和value的⽤法基本相似,就不做重复说明。4.4、enable
enable绑定⼀般⽤于是否启⽤标签元素,⼀般⽤于表单元素的启⽤和禁⽤。和disabled相反,对应的
值也是bool类型。
<div>
<input type="text" data-bind="enable:IsMen"/>
</div>
<script type="text/javascript">
//1.定义ViewModel
var myViewModel = {瘰疬丸
Name: ko.obrvable("Lilei"),
Profession: ko.obrvable("软件⼯程师"),
Age: ko.obrvable(40),
IsMen:ko.obrvable(true)
};
//2.激活绑定
ko.applyBindings(myViewModel);
myViewModel.IsMen(fal);
</script>
由于IsMen属性变成了fal,所有对应的⽂本框会显⽰禁⽤状态。
4.5、disabled
和enable相反,⽤法和enable类似。
4.6、options
不完美的她
上⽂中在使⽤lect的绑定时候使⽤过options,它表⽰lect标签的option的集合,对应的值为⼀个数组,表⽰这个下拉框的数据源。可以使
⽤obrvableArray启⽤对这个数据源的监控。⽤法见上⾯。
4.7、html
text绑定实际上是对标签innerText的设置和取值,那么同理,html绑定也是对innerHTML的设置和取值。它对应的值为⼀段html标签。
4.8、css
css绑定是添加或删除⼀个或多个样式(class)到DOM元素上。使⽤格式:
<style type="text/css">
.testbold {
background-color:powderblue;
}
</style>
<div data-bind="css:{testbold:myViewModel.Name()=='Lilei'}">aaaa</div>
var myViewModel = {
Name: ko.obrvable("Lilei"),
Profession: ko.obrvable("软件⼯程师"),
Age:ko.obrvable(40)
};
该div会显⽰背景⾊。
如果需要增加或移除多个样式,只要稍微改下即可,⽐如:
<div data-bind="css:{testbold:myViewModel.Name()=='Lilei',testborder:myViewModel.Profession()=='PHP⼯程师'}">aaaa</div>
4.9、style
如果css绑定的作⽤是向标签动态添加或移除class样式,那么style绑定的作⽤就是想标签动态添加或移除某⼀个样式。⽐如:
<div data-bind="css:{ padding: 0px; color: rgb(0, 0, 255); line-height: 1.5 !important;">>aaaa</div>
如果是添加或者移除多个,同css绑定的⽤法
4.10、attr
attr绑定主要⽤于向标签添加移除某⼀个或多个属性(包括⾃定义属性),永和和css类似。
4.11、click
click绑定表⽰在对应的DOM元素上⾯添加点击事件的执⾏⽅法。可以在任意元素上⾯使⽤。
<div>
<input type="button" value="测试click绑定" data-bind="click:ClickFunc" />
</div>
var myViewModel = {
ClickFunc:function(){
alert($(event.currentTarget).val());
}
};
ko.applyBindings(myViewModel);
event.currentTarget表⽰当前点击的DOM元素。有时为了简便,我们直接使⽤匿名函数的⽅式绑定,⽐如:
<div>
<input type="button" value="测试click绑定" data-bind="click:function(){
alert('点击了');
}" />
</div>
但是这种将js揉到html⾥⾯的写法让博主难以接受,并且觉得维护起来相对不⽅便,尤其是点击事件⾥⾯的逻辑略复杂时。所以,如⾮必须,不建议直接写这种匿名函数的⽅式。
4.12、其他
关于data-bind的所有绑定,可以看官⽹上⾯的介绍,这⾥就不⼀⼀列举了。需要⽤的时候去官⽹上查下就好了。看看官⽹上⾯列举的所有绑定:
5、Json对象和监控属性的转化及关系