今天整理一下WeX5的绑定机制。
成都创新互联自2013年起,是专业互联网技术服务公司,拥有项目成都网站建设、网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元福贡做网站,已为上家服务,为福贡各地企业和个人服务,联系电话:13518219792原生的问题
假设我们做一个订单系统,需要显示商品单价,然后可以根据输入数量计算出总价并显示出来。使用原生代码也很容易实现,效果:
代码如下:
Price:嗯,蛮简单的!哦,对了,我们一次展示50件商品,同时又有10类这样的展示,还有买5盒冈本送一根油条这样的各种促销呢……
所以,你知道原生实现的问题了吧:
随着 UI 和数据交互的增多,代码量迅速增长,难以维护
基于 Dom 查询,id 或 class 的命名难以管理
代码耦合度高,难以复用
WeX5的解决之道
为了解决上述问题,WeX5中引入了knockoutjs(下文简称ko)这个MVVM库。
为何选用ko而不是Angular一类比较全面的框架?Angular是好,但这么大而全的框架,没有经过足够的实战测试的话,很多坑都不会被暴露出来。而ko是一个轻量级的MVVM库,专注于实现数据与视图的绑定,本身并不提供 UI 类和路由等功能,所以非常简单稳定。同时,由于他出来也已经有些年头了,现在是比较成熟的框架了。所以在做一些移动页面开发时,ko无疑是一个比较好的选择。另外,关于MVVM小茄就不多说了,一图以蔽之:
ko建立在3大核心特征之上(官网介绍):
1. 可观察对象与依赖跟踪 (Observables and dependency tracking):使用可观察对象在模型数据之间设立隐性关系链,用于数据转换和绑定。
2. 声明式绑定 (Declarative bindings):使用简单易读的语法方便地将模型数据与DOM元素绑定在一起。
3. 模板 (Templating):内置模板引擎、为你的模型数据快速编写复杂的 UI 展现。
下面简单说说ko的几大概念:
可观察对象
使用ko重写上面的例子(自定价格,这也是我小时候的愿望之一):
代码是这样的:
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()。
ko.observable(p):见名知义、这个就是设置可观察对象的方法,传入的参数p就是初始化的值,这里的参数可以是基本数据类型,也可以是一个json对象。被设置为可观察对象后就意味着系统会一直观察这个值。无论是ViewModel中的p还是被绑定对象的p发生变化都会引起刷新事件,将所有用到这个值的地方都更新到最新状态。显然,可观察对象是比较消耗性能的,所以对于不需要动态变更的值(如价格)则不要设置为可观察对象,当然还是需要放入ViewModel中进行集中初始化。
注意:ko.observable(p)返回的可观察对象是一个函数对象,所以读取可观察对象需要使用price()这种方式;同样的,设置可观察对象需要使用price(newValue)这种方式。比较贴心的是,设置的时候支持链式写法:ViewModel.price(100).account(10)。
ko.pureComputed()就是所谓的依赖跟踪了,这里是单价*数量等于总价,注意这里不能直接用this.sum = this.price() * this.account();来指定sum,这种写法不能动态刷新被绑定的对象,只是动态改变了sum变量,但要去刷新绑定对象还需要其他操作。所以,与计算相关的绑定值都要用ko的计算函数来设置。当然,返回的也是一个函数对象。另外,ko还有一个computed函数,也可以用其来进行设置,不过推荐使用pure的方式,以提高性能。
注意这里的写法:ko.pureComputed(fn, this),也就是将fn绑定到ViewModel执行环境中,其实就是js中的call/apply。因为在执行ko内部函数的时候,this为ko对象,所以为了得到ViewModel对象,需要通过上面的写法传入this。当然也可以在ko函数外部用that保存ViewModel对象,然后在ko函数内部使用that来调用ViewModel对象。像这样:
定义好ViewModel构造函数后便实例化了一个ViewModel对象,然后使用了ko.applyBindings()的方式来使得绑定生效,这一步不要漏掉了。
使用ko的页面简单模式:
// js Codevar 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方法则不会刷新界面。下面是一个简单例子: