MVVM框架中Angular是好,但这么大而全的框架,学习难度可不低呢,上手起码也得要个一两周吧。而knockoutjs专注于数据绑定,只需一两天就可以投入使用了,学习成本不要太低!在前端进化如此迅速的时代,学习成本也是不得不考虑的一个因素。很多时候其实我们的项目并没那么复杂,也并不需要万能的框架,更需要的反而是简单顺手的工具。
Before Knockoutjs
假设我们做一个订单系统,需要显示商品单价,然后可以根据输入数量计算出总价并显示出来。使用原生代码也很容易实现,效果:
代码如下:
<!--HTML code--> Price: <span id="price"></span><br /> Account: <input type="text" id="account" value="" placeholder="请输入数量" /><br /> sum: <span id="sum"></span> //js code var priceNode = document.getElementById('price'), accountNode = document.getElementById('account'), sumNode = document.getElementById('sum'), price = 100, account = 11, sum = price * account; //初始化。 priceNode.innerText = price; accountNode.value = account; sumNode.textContent = sum; //监视 View层的用户输入 accountNode.addEventListener('keydown', function (e) { window.setTimeout(function () { account = accountNode.value; sum = price * account; sumNode.textContent = sum; },10); });
嗯,蛮简单的!哦,对了,我们一次展示50件商品,同时又有10类这样的展示,还有买5盒冈本送一根油条这样的各种促销……
所以,你知道原生实现的问题了吧:
"color: #ff0000">Knockoutjs简介
Knockoutjs(下面简称ko)就是为了解决上述问题而出现的,他是一个轻量级的MVVM库,专注于实现数据与视图的绑定,本身并不提供 UI 类和路由等功能,上手非常快。同时,由于ko出来已经有些年头了,已经是比较成熟的框架了。在做一些动态显示比较多的页面时,ko无疑是一个比较好的选择。关于MVVM楼主就不多说了,一图以蔽之:
ko建立在3大核心特征之上(官网介绍):
1. 可观察对象与依赖跟踪 (Observables and dependency tracking):使用可观察对象在模型数据之间设立隐性关系链,用于数据转换和绑定。
2. 声明式绑定 (Declarative bindings):使用简单易读的语法方便地将模型数据与DOM元素绑定在一起。
3. 模板 (Templating):内置模板引擎、为你的模型数据快速编写复杂的 UI 展现。
使用ko非常简单,直接到官网(http://knockoutjs.com/index.html)下载并用<script>引入即可。
可观察对象
使用ko重写上面的例子(自定价格,这也是我小时候的愿望之一):
代码是这样的:
<!--HTML Code--> <div id="one"> Price: <input type="text" data-bind="value: price" placeholder="请输入单价" /><br /> Account: <input type="text" data-bind="value: account" placeholder="请输入个数" /><br /> sum: <span data-bind="text: sum"></span> </div> // js Code var ViewModel = function(p, a) { //设置为可观察对象并以参数p、a初始化 this.price = ko.observable(p); this.account = ko.observable(a); //调用ko函数的时候将this传入,否则执行ko.pureComputed内部代码时,this为ko,ko.price()报错。 this.sum = ko.pureComputed(function() { //因为可观察对象是一个函数对象,所以要用 price()来读取当前值。 //设置值使用price(NewValue),支持链式写法:this.price(12).account(3) return this.price() * this.account(); }, this); }; var vm = new ViewModel(135, 10); //应用该绑定,绑定开始生效 ko.applyBindings(vm);
1)先看HTML代码:
可以看到在每个标签中都加入了一个 data-bind = "XX:OO" 这样的键-值对。这个就是 ko 的绑定语法,XXOO代表什么东西呢?(XXOO?楼主还是个孩子啊…)从例子可以看到XX为标签的属性,可以是text、value、class、checked等标签属性,其实也可以是click、focus、load等DOM事件。OO看起来像是一个变量,实际上并不是变量,而是一个函数对象,执行这个函数(带个())就能得到相应的绑定值。通过XXOO就可以将元素的属性或事件跟js中的函数对象绑定在一起(XXOO了就要相互负责哈),这就是ko的声明式绑定。绑定的定义其实就是一个观察者模式,只不过这是双向的绑定,发布者和订阅者相互订阅了对方的消息而已,这就是MVVM的双向绑定。ko双向绑定的结果就是一方变化就可以自动更新另一方,也就是通过ViewModel将数据和表现层紧紧绑定在一起了。绑定的效果类似于:
2)再看看js代码:
可以看到js中定义了一个ViewModel对象,在对象中对HTML中绑定的OO进行了操作。这里主要有两个操作: ko.observable()和ko.pureComputed()。
"htmlcode">
var that = this; this.sum = ko.pureComputed(function() { return that.price() * that.account(); });
定义好ViewModel构造函数后便实例化了一个ViewModel对象,然后使用了ko.applyBindings()的方式来使得绑定生效,这一步不要漏掉了。
使用ko的页面简单模式:
<!--HTML Code--> <span data-bind="text: bindtext"></span> // js Code var viewModel = { bindtext: ko.observable('initValue') }; ko.applyBindings(viewModel);
总结起来就是:HTML中使用data-bind="XX: OO"声明绑定,js中建立ViewModel并设置可观察对象,最后应用绑定。
可观察对象数组
再看看可观察对象数组的使用方法,在ko中可不能像js一样数组和变量混用,对于数组对象就要用ko.observableArray([…,…])这种形式,同样的,数组元素也可以是基本类型也可以是json对象。ko中的可观察对象数组有一系列的数组操作方法,如slice()、sort()、push()这种,效果跟原生的js数组操作方法一样,只是通过ko方法所做的改动会通知到订阅者从而刷新界面,但js方法则不会刷新界面。下面是一个简单例子:
<!--HTML Code--> <select data-bind="options: list"></select> // js Code var vm = { // list: ko.observableArray() list: ko.observableArray(['Luffy','Zoro','Sanji']) }; ko.applyBindings(vm);
关键点:ko监控的是数组的状态,而不是元素本身的状态。也就是说当数组状态变化(增减元素)的时候会触发ko事件引起绑定对象的刷新,但数组内部元素的变化(如:值变化)则不被监控不能触发ko事件。例如:
在控制台中使用原生方法将Luffy动态改成Lucy是不会刷新UI页面的,而使用ko的数组操作改动数组则会立即刷新页面,值得注意的是在刷新的时候,也会将之前的改动刷新出来(Luffy > Lucy)。也就是说其实js内存中的变量是已经改变了,但是还缺少一个刷新DOM的动作。这里大家可以看到,读取数组的方法是vm.list()[0],因为list也是一个函数对象,执行返回值才是我们想要的list内容。同理,也可以通过 vm.list(["妹子","妹子","妹子"]) 这样的方式重置可观察对象数组,也能立即刷新UI。
如果需要将数组元素的改动也动态反应到UI上,需要将数组元素也设置为可观察对象,然后使用ko的方法改变数组元素值。注意,是使用ko的方法 list()[0]("Lucy")!
操作可观察对象数组的方法有两类,一类是与原生js数组方法同名的:pop, push, shift, unshift, reverse, sort, splice,这一部分与js原生方法的用法和效果都一样,就不再赘述了。
另外一些方法是js中没有的,主要有以下几个:
"color: #ff0000">总结
本篇主要简单介绍了knockoutjs中最重要的概念:可观察对象(数组)。可观察对象实质上是一个函数对象,通过ko方法操作可观察对象时可以动态刷新UI展现,这个是推荐做法。同时,也可以通过原生的js方法操作可观察对象,只是原生方法并不会刷新UI展现,需要等到下一次刷新事件时才会被刷新到UI中。