knockout.js 框架使用小记
Knockout js 使用心得条目:
1 knockout js是个轻量级的js框架,在knockout官网下载之后,可以引入自己的html中。knockout js的使用并不需要jQuery配合,但我们也可以在jQuery之后自己的js文件之前引入knockoutjs
2 knockout js是一个MVVM(Model View Viewmodel)框架, 其他还有MVC(Controller),MVP(Presenter)框架
3 knockout js 是创建一些监控变量和监控数组和事件,并将这些变量,数组,事件通过data-bind属性统统绑定在html上。好处:1省去了在js文档中要写绑定和获取元素的烦恼,因为某个html元素要获取的内容和事件已经绑定好了 2 如果元素的内容或者属性有变化,不需要再查找元素,更改属性,直接修改绑定的变量,数组和事件,html元素就会动态地更新
4 knockout的引入:
<script type="text/javascript" src="./js/jquery-2.2.3.js"></script> <script src="./js/knockout-3.4.0.js"></script> <script type="text/javascript" src="./js/demou1.js"></script>
5 knockout的结构:
在js文件中,需要引入的初始数据(一般来说都是不变的数据)都可以在model外定义,可变的数据都要定义在model内部
var variable1 = "..."; var variable2 = "..."; var variableArray = ["..."]; var variableObject = {}; /*...一系列初始量的定义, 这些值是作为外部数据,要传入这个model的...*/ function ViewModel(){ var self = this;//将this赋值给self,这样方便内部不同域时使用this /* * 自己定义的监控变量,监控数组,还有事件写在这里 */ } ko.applyBindings(new ViewModel());
最后需要应用这个ViewModel,注意每个项目只可以应用一次这个Model
严重注意一点:如果在body的末尾引入script,那么就可以直接向上边这样写代码了;如果在头部引入(推荐),那么就需要将所有代码包裹起来(让DOM树结构完整了再运行代码),两种方法,可以用jQuery包裹,也可以用纯js的window.addEventListener(“load”, function(){}, false)来包裹,个人觉得第二个更好,少用jQuery可以节省运行时间
window.addEventListener("load", function(){ /*...所有代码...*/ }, false); $(function(){ /*...所有代码...*/ });
6监控变量:
监控变量的定义
self.variable1 = ko.observable("..."); self.variable2 = ko.observable(100); self.variable3 = ko.observable(variable1); self.variable4 = ko.observable({ name: "alex", age: 18 });
这个括号里面就是这个监控变量的值,这个值可以是字符串,可以是数字。这样的话,模型就会实时监控这个变量,任何html元素使用了这个变量,当我们在模型中改变这个变量的时候,html中的值就会改变。
监控变量的值获取
var value = self.variable1();
注意,值后边一定要有括号,因为监控的本质是个函数,执行这个函数会返回所监控的内容
这个括号里还可以写外部定义的字符串或数字
监控变量的值更新
self.variable1("abc"); self.variable2(self.variable2() + 1); self.variable1().school = "123"
在括号内赋值,或者改变数值,来更新监控变量。注意第二个,更新的时候是在原有的上边加1
7 监控数组
监控数组的定义:使用ko.observableArray()来定义
self.arr = ko.observableArray([]); self.arr1 = ko.observableArray([{}, {}, {}]); self.arr2 = ko.observableArray(variableArray);
监控数组里面可以放空数组,可以放对象组成的数组,可以把模型外的数组引入
注意,如果想使用对象,也推荐将对象作为数组的元素来使用,方便用foreach:绑定,如果只是想用对象的话,也可以用ko.observable()来监控
监控数组的获取
var array = self.arr();
必须要有括号。获取到的是数组,也就是之前括号里面的监控的值
监控数组的更新
self.arr([{ "name": "Lee" }, { "name": "alex" }])
当然监控数组也可以用js的数组方法来更新,
比如self.arr.push(123) 和 self.arr().push(123)效果一样的,不过推荐后者,与监控变量一样的方法,更清晰。
监控数组可以用的方法比如.push() .pop() .unshift() .shift() .slice() .reverse() .sort() .splice()
注意.sort()方法,我们知道排序时必须要传一个比大小的函数,不然会按照字符串来比较
self.arr().sort(function(a, b){ if(a < b){ return -1; }else{ return 1; } });
从小到大还是从大到小就是调整-1和1的位置
因为数组的上述方法都是可以直接改变数组的,所以我们可以用self.arr().方法()直接使用,但是无论字符串还是数字都没有可以改变自身的方法,所以就不能这样更新了。
其实监控变量还是监控数组本质都可以用self.content(self.content()变化)来更新, 获取都是用self.content()来获取
8 事件:
通过self.事件名 = function(){...};来定义事件,事件可以用于被触发时,更新监控数据或者做其他操作
self.divClick = function(){ self.arr1().push("click"); // 更新数据 console.log("Click"); }; <div data-bind="html: variable1, event: {click: divClick}"></div>
9 绑定:通过在html标签内引入data-bind = “” 来绑定标签和监控数据(变量,数组,事件)
详细绑定可以参考knockout的文档http://knockoutjs.com/documentation/introduction.html
这里说几个比较常用的:
多个事件绑定用,号隔开,同一种绑定的不同类型,用: {,}来区别, style里用backgroungColor这种写法,而不用background-color这种写法
html绑定和text绑定:
我们在jQuery中知道$(..).html() 和 $(..).text()的作用,可以设置和获取某元素的内容,区别在于html()方法一旦遇到可以转换成标签的内容就会变成html标签,可以动态生成内部元素,而text()方法不管遇到什么都会作为这个元素的文本内容体现
那么这里的绑定也是这个意思:
使用方法:
<div data-bind="html: variable2"></div>
这个html:后的variable2 一定是在js中已经定义好了的监控变量 self.variabl2 = ko.observable(..)
visible绑定:
self.flag1 = ko.observable(true); self.flag2 = ko.observable(false);
定义两个保存true和false的状态值
<div data-bind="html: variable1, visible: flag2"></div>
如果visible: false状态,就会自动隐藏,如果visible: true状态就会显现。而这里的隐藏很有用,隐藏之后并不占位,可以用来实现动态的列表等
attr绑定:用来绑定并动态修改元素的行内属性
self.src = ko.observable("...");
self.alt = ko.observable("...");
定义了行内属性值
<img src="" alt="" data-bind="attr: {src: src, alt: alt}"/>
与jQuery相似的是,对于表单元素input等,或者标签行内有value的属性,可以用value来绑定
data-bind=”value: ...”
style绑定:用来绑定并动态修改元素的样式
self.displayBlock = ko.observable("block"); self.backgroundColor = ko.observable("red"); <div data-bind="style: {display: displayBlock, backgroundColor: backgroundColor}"></div>
也可以用事件绑定了,
self.backgroundColor = function(){ return "rgb(23, 45, 67)"; };
只不过backgroungColor: backgroundColor()来调用
<div data-bind="html: variable2, style: {display: displayBlock, backgroundColor: backgroundColor()}"></div>
css绑定:这个是添加css类的,也就是给元素添加或动态修改class的
比如我在css中定义了
.red { background-color: red; }
我在js中,监控了这个类名
self.addRedClass = ko.observable("red");
那么我可以绑定到标签上
<div data-bind="html: variable2, css: addRedClass"></div>
该标签就可以自动获取并添加一个类 red,相当于class = red
也可以用方法来获取,动态修改类,来切换一些复杂的预先定义好的样式:
self.addRedClass = function(){ return "red"; };
只不过这个时候也是要用addRedClass()来获取,
<div data-bind="html: variable2, css: addRedClass()"></div>
事件绑定类:
click绑定:
self.divClick = function(){ self.arr1().push("click"); // 更新数据 console.log("Click"); };
定义点击要触发的方法
<div data-bind="html: variable2, click: divClick"></div>
submit绑定:
self.formSubmit = function(){ self.divClick(); return false;//阻止默认事件,也是默认值,可以不写return false //return true;//允许默认事件 };
定义submit的方法,提交方法要绑定在form元素上,按回车的时候触发
<form action="" data-bind="submit: formSubmit"></form>
对于任何事件,click或者submit,或者之后的event包含的所有事件,使用data-bind都是阻止默认行为的,如果想要开启默认行为就要return true;
event绑定:
应该算是所有事件都适用,可为一个元素绑定多个事件
self.rightClick = function(){ console.log("rightClick"); return false; }; <div data-bind="html: variable2, event: {click: divClick, contextmenu: rightClick}"></div>
同时绑定了左击和右击事件
value绑定和textInput绑定:
他们两个都可以用来绑定input,select,textarea元素,
value: 监控元素或者函数(), valueUpdate: ‘keyup’
后边还可以有一个参数来指明,什么时候更新这个value,使用valueUpdate: 可以是’keyup’弹起触发 ‘keypress’按下触发(不松手会持续触发) ‘afterkeydown’按下后触发
<input type="search" data-bind="value: inputValue, valueUpdate: 'afterkeydown', event: {click: inputClick, keyup: inputKeyUp}" />
实际上,如果你要浏览器边输入边检测输入的内容的话,textInput绑定最合适,因为他可以不加附加参数,并且检测所有输入的值
<input type="search" data-bind="textInput: inputValue" />
foreach绑定:
如果你想要根据已有的数据动态生成一些元素,并添加到父元素内,或者动态管理元素的内容,那么对父元素采用foreach绑定最合适了。
之前我们知道用html绑定也可以给元素添加子元素,并且这个子元素也可以应用绑定,问题是,这样生成的子元素,虽然我写了绑定,但是无法触发。
self.variable2 = ko.observable("<span data-bind='click: divClick'>123</span>");
<div data-bind="html: variable2"></div>
因为模型应用的时候,他刚刚生成这个元素,并没有解析他的绑定事件,所以绑定不了。
解决办法:
单独对这个元素绑定一下模型,
模型结尾,
var viewmodel = new ViewModel(); ko.applyBindings(viewmodel); ko.applyBindings(viewmodel, $("span")[0]);
这样我们绑定的还是同一个模型,第一次把DOM里已经有的元素和事件绑定了,第二次绑定那些动态生成的元素,不是jQuery元素,一定是DOM元素, document.getElementsByTagName("span")[0]
或者$("span")[0] 或者$("span").get(0)
另一种解决办法就是foreach绑定:
这个绑定经常用于比如要给ul - li或者ol - li动态添加li的时候使用,也可以用于动态添加几组元素比如,动态添加三组 h3-p-span的组合到父元素中。
并且foreach绑定可以绑定并解析事件,无需在模型末尾再绑定元素。这时就要用observableArray([])了,数组里面包含几个对象元素,那么就会产生几个子元素。
父元素用foreach: 监控数组,写一个子元素, 子元素内用$data.来获取每个对象中的值,作为相应的绑定内容
self.arr3 = ko.observableArray([{ "name": 'lee', "liEvent": function(){ console.log("click"); } }, { "name": 'george', "liEvent": function(){ console.log("click"); } }, { "name": 'alex', "liEvent": function(){ console.log("click"); } }]);
<ul data-bind="foreach: arr3"> <li data-bind="html: $data.name, click: $data.liEvent"></li> </ul>
这个时候就可以发挥数组的方法的灵活性了,就可以操作数组,数组里面可以添加对象等。也可以自己写函数让每个对象内容不同,这样绑定的结果也会不同了。
使用knockout时,经常用的数组.forEach()方法和indexOf()取某元素索引的方法
self.arr3().forEach(function(item){ if(item.name == "george"){ console.log(self.arr3()[self.arr3().indexOf(item)]); } });
对于,html刚加载时的事件window.onload, 或者屏幕缩放时的动态捕捉事件window.onresize, 可以绑定在body上
<body data-bind="event: {load: windowLoad(), resize: windowResize()}">
...........未完待续...........