今天整理一下WeX5的绑定机制。

原生的问题

假设我们做一个订单系统,需要显示商品单价,然后可以根据输入数量计算出总价并显示出来。使用原生代码也很容易实现,效果:

代码如下:

Price:

Account:

sum:

//js codevar 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盒冈本送一根油条这样的各种促销呢……

所以,你知道原生实现的问题了吧:

随着 UI 和数据交互的增多,代码量迅速增长,难以维护

基于 Dom 查询,id 或 class 的命名难以管理

代码耦合度高,难以复用

WeX5的解决之道

为了解决上述问题,WeX5中引入了knockoutjs(下文简称ko)这个MVVM库。

为何选用ko而不是Angular一类比较全面的框架?Angular是好,但这么大而全的框架,没有经过足够的实战测试的话,很多坑都不会被暴露出来。而ko是一个轻量级的MVVM库,专注于实现数据与视图的绑定,本身并不提供 UI 类和路由等功能,所以非常简单稳定。同时,由于他出来也已经有些年头了,现在是比较成熟的框架了。所以在做一些移动页面开发时,ko无疑是一个比较好的选择。另外,关于MVVM小茄就不多说了,一图以蔽之:

ko建立在3大核心特征之上(官网介绍):

可观察对象与依赖跟踪 (Observables and dependency tracking):使用可观察对象在模型数据之间设立隐性关系链,用于数据转换和绑定。

声明式绑定 (Declarative bindings):使用简单易读的语法方便地将模型数据与DOM元素绑定在一起。

模板 (Templating):内置模板引擎、为你的模型数据快速编写复杂的 UI 展现。

下面简单说说ko的几大概念:

可观察对象

使用ko重写上面的例子(自定价格,这也是我小时候的愿望之一):

代码是这样的:

Price:

Account:

sum:

// js Codevar 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()。

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对象。像这样:

var that = this;this.sum = ko.pureComputed(function() {

return that.price() * that.account();

});

定义好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方法则不会刷新界面。下面是一个简单例子:

// js Codevar 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!

操作可观察对象数组的方法有两类,一类是与原生js数组方法同名的:pop, push, shift, unshift, reverse, sort, splice,这一部分与js原生方法的用法和效果都一样,就不再赘述了。

另外一些方法是js中没有的,主要有以下几个:

remove(someItem) --

删除所有值与someItem相等的元素项并将它们以数组形式返回,这里的意思就是说你可不能直接list.remove(0)来删除第一项,而是要用list.remove(list()[0])

这种形式来删除。总而言之,传入的参数必须是元素项的值,可以用list()[0]

的形式,也可以直接输入值的字符串(比如“Luffy”这种)。

remove(function(item) { return item.age < 18;}) --

删除所有age属性小于18的元素项并将它们以数组形式返回,这种用法跟平常的数组高阶函数没什么区别。Item作为高阶函数的参数传入,遍历数组时,当高阶函数返回值为真值时就删除该项,否则转到下一项。

removeAll(['Chad', 132, undefined]) -- 删除所有值与 'Chad' 或 123 或

undefined 相等的元素项并将它们以数组形式返回。

removeAll() -- 删除所有项并以数组形式返回。

小窍门:在处理可观察对象时,若对象数量众多而且交互频繁的情况下,每次变更都立即刷新的话会非常消耗性能,这个时候可以使用扩展 myObservableArray.extend({ rateLimit: 1000 }) 来设置延迟刷新。比如在不断往可观察对象数组中插入元素时,可以设置一个周期时间1000ms,让1000ms内的所有操作集中到一次刷新中去,避免频繁操作 DOM 带来的性能恶化。

WeX5中如何使用ko?

WeX5作为Html5 开发工具界的翘楚,少不了集成优秀的ko框架,使用的方法非常简单:在可视化编辑器中指定组件的bind属性,然后在js代码中操作相应绑定值。

先在可视化编辑器中指定:

这种方法在hello world篇也有简单介绍,不熟悉的同学可以先去看看哈。通过可视化编辑器我们就可以绑定相应的属性或者事件了,这里我们为 bind-ref 绑定了一个字符串“hello world”,至于其他的属性和事件将在下一篇中介绍。绑定后我们打开代码编辑器,发现里面并没有出现1)那样的绑定代码。那绑定代码写到哪里去了呢?请打开HTML源码:

可以看见代码中出现了“bind-ref='Hello World’”这个跟上文说的data-bind是不是很相似呢?这里WeX5将每个组件可以绑定的属性都添加到可视化编辑器中,这样就不用再去记某个组件可以绑什么属性了,鼠标指哪就绑哪!当然绑定字符串意义不大, 我们一般会绑定一个变量(实际上是返回值为所需变量的函数对象)。例如:

这里绑定了text为myText,这种形式的绑定为直接绑定在model对象下的,所以可以在js源码中的Model下操作这个myText对象。

1 define(function(require){ 2 var $ = require("jquery"); 3 var justep = require("$UI/system/lib/justep"); 4 5 var Model = function(){ 6 this.callParent(); 7 this.myText = justep.Bind.observable("bind!"); 8 }; 9 Model.prototype.button2Click = function(event){ 10 this.myText.set("changed"); 11 }; 12 return Model; 13 }); 14

可以看到ko组件已经被封装到justep的Bind对象里面去了,另外对可观察对象的操作也跟ko中有点不同,这里采用的是set/get分别来设置和获取可观察对象的值。其他诸如compute等大部分方法的用法跟ko中一致。

总结

本篇主要简单介绍了WeX5中数据绑定的由来和背后的优秀框架(knockoutjs),着重介绍了ko中最重要的概念:可观察对象(数组),然后简单示范了如何在WeX5中使用绑定机制以及 WeX5中的绑定与ko中的差异点。

关于可观察对象的简单介绍就到这里了,下一篇将具体介绍各种绑定的用法!码字不易,随手点赞哈~

参考资料:

ko 绑定html,WeX5的正确打开方式(3)——绑定机制相关推荐

  1. 【分享】WeX5的正确打开方式(5)——绑定机制

    今天继续WeX5的绑定机制. 需求分析 记账本要实现的效果就是可以展示所有账单,还能实时动态编辑每一笔账单,官方案例的效果图如下: 展示页: 编辑页 个人觉得官方案例加入了许多元素,不熟悉的同学每一个 ...

  2. 【分享】WeX5的正确打开方式(1)

    最近在研究WeX5,想在这里记录下使用过程中的点滴,今天先把之前已经掌握的分享一下.         WeX5官方的开发指南难度系数较大,面向的受众可能是已经敲过上万行代码的html5 app开发者. ...

  3. 叮!丰巢智能柜那些贴心服务的正确打开方式

    年底了,我的快递特别多,这个时候真的是被丰巢智能柜圈粉了,以前我总觉得,丰巢智能柜就是一个存放快递的地方,万万没想到,丰巢智能柜还有这么多的贴心服务,今天就给各位小姐妹安利一下丰巢智能柜的那些正确打开 ...

  4. C# 倍福ADS的正确打开方式,使用AdsRemote组件优雅的通过ADS通讯

    C# 倍福ADS的正确打开方式,使用AdsRemote组件优雅的通过ADS通讯,支持WPF窗体控件的绑定机制,做上位机页面很方便,大大节省了开发时间. 倍福的官方文档给的例子我就不多说了,今天介绍一种 ...

  5. opengl 贴图坐标控制_材质贴图正确打开方式

    哈喽,各位观众朋友们好鸭~欢迎来到讲道理画图的地方,我是黄玮宁. 最近呀经常有小伙伴来问我那些不同通道的材质贴图该怎么用,而且频率不是一般的高,所以我觉得有必要来说说这些通道贴图的用法了. 视频版(B ...

  6. Console控制台的正确打开方式

    Console控制台的正确打开方式 console对象提供了访问浏览器调试模式的信息到控制台 -- Console对象|-- assert() 如果第一个参数断言为false,则在控制台输出错误信息| ...

  7. 任务队列和异步接口的正确打开方式(.NET Core版本)

    layout: post title: 任务队列和异步接口的正确打开方式(.NET Core版本) category: dotnet core date: 2019-01-12 tags: dotne ...

  8. log python_基于Python log 的正确打开方式

    保存代码到文件:logger.py import os import logbook from logbook.more import ColorizedStderrHandler import sm ...

  9. python四舍五入round_四舍五入就用round( )?Python四舍五入的正确打开方式!

    四舍五入就用round( )?Python四舍五入的正确打开方式! 2018-09-22 21:40 阅读数 4 <>round( )函数简介 菜鸟教程中介绍到,round() 函数作用就 ...

最新文章

  1. oracle字符集与客户端
  2. 微信小程序云开发用户身份登录_云开发版的微信商城小程序第一章
  3. Ubuntu xrdp 遠端桌面連線
  4. python列表的特点_python基础(一)列表、集合和元组的基本特性
  5. Linux学习总结(43)——企业运维最常用的150个Linux命令
  6. Python无限播放励志语句
  7. Red5服务器端报错:无法解析类型ResourcePatternResolver
  8. 送书丨超级畅销书《漫画算法》50 本免费送!
  9. Idea 中使用Lombok 编译报找不到符号
  10. 咸鱼の软构实验感想(1)
  11. golang-ffmpeg-goav拉流解码器,支持视频拉流解码并转换为YUV、BGR24或RGB24等图像像素数据
  12. 三星Galaxy之父×××网秦,网秦安全能否脱胎换骨?
  13. H5--大概的,没事看看
  14. python调用函数示例_Python使用execjs运行JS函数示例,python,execJS,例子
  15. linux中查看系统进程的四种方法
  16. vue element-ui中有关表格中的数据整条显示红色/绿色等等颜色的问题
  17. Vue 新手学习笔记:vue-element-admin 之按钮级权限管控
  18. 青龙面板+xdd-plusQQ机器人便捷登陆查询保姆级搭建教程
  19. Chromium插件(Plugin)模块(Module)加载过程分析
  20. 可燃冰 flammable ice

热门文章

  1. 《弃子长安》第十五章 人断惊崖
  2. mysql 执行错误1395_主义 - 常规错误:1395无法删除连接视图
  3. 使用PyInstaller遇到的坑坑洼洼
  4. 最详细的golang + 私库(gitlab gitee) 模块开发 这一篇文章解决所有问题
  5. 【Docker】搭建Docker私库Harbor
  6. Vue报错------did you register the component correctly? For recursive components, make sure to provide
  7. C语言编写Python包,使用C语言编写Python扩展1——Hello World
  8. beecloud支付后端java
  9. socketio单聊,群聊
  10. 开源仿google plus的wordpress主题