迷你MVVM框架 avalonjs 学习教程15、属性监听与模块通信
avalon的ViewModel对象从其内部EventManager里继承了三个方法,$watch、$unwatch、$fire三个方法,它们就是我们本节的主题。
词如其名,非常直白,一看就知道做什么。我们先从$watch方法说起,它能监听当前的VM第一层的监控属性 与 计算属性,如果某属性是一个对象,想监控其子孙属性,就需要定位到此对象上使用$watch回调了。$watch回调会默认传入先后两个属性值。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="avalon.js" ></script>
- <script>
- var model = avalon.define({
- $id: "test",
- aaa: "2",
- bbb: "2",
- $ccc: "1",//这是非监控属性
- ddd: "1",//这是非监控属性
- $skipArray: ["ddd"],
- click: function(a) {
- model[a] = new Date - 0
- }
- })
- model.$watch("aaa", function(a, b) {
- console.log("aaa", a, b)
- })
- model.$watch("bbb", function(a, b) {
- console.log("bbb", a, b)
- })
- model.$watch("$ccc", function(a, b) {
- console.log("$ccc", a, b)
- })
- model.$watch("ddd", function(a, b) {
- console.log("ddd", a, b)
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('aaa')">{{aaa}}</div>
- <div ms-click="click('bbb')">{{bbb}}</div>
- <div ms-click="click('$ccc')">{{$ccc}}</div>
- <div ms-click="click('ddd')">{{ddd}}</div>
- </body>
- </html>
如果属性非常多,我们可以监听$all这个特殊的属性名来得知所有属性的变动状况。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="../avalon.js" ></script>
- <script>
- var model = avalon.define({
- $id: "test",
- aaa: "2",
- bbb: "2",
- $ccc: "1",
- ddd: "1",
- $skipArray: ["ddd"],
- click: function(a) {
- model[a] = new Date - 0
- }
- })
- model.$watch("$all", function(name, a, b) {
- console.log(name, a, b)
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('aaa')">{{aaa}}</div>
- <div ms-click="click('bbb')">{{bbb}}</div>
- <div ms-click="click('$ccc')">{{$ccc}}</div>
- <div ms-click="click('ddd')">{{ddd}}</div>
- </body>
- </html>
我们也可以用$fire更改属性值。这样就可以打破不能触发非监控属性的回调的藩蓠,但要注意死循环,需要自己比较新旧值是否真的发生改变才触发。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="../avalon.js" ></script>
- <script>
- var model = avalon.define({
- $id: "test",
- aaa: "2",
- bbb: "2",
- $ccc: "1",
- ddd: "1",
- $skipArray: ["ddd"],
- click: function(a) {
- var old = model[a]
- model.$fire(a, new Date - 0, old)
- }
- })
- model.$watch("$all", function(name, a, b) {
- console.log(name, a, b)
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('aaa')">{{aaa}}</div>
- <div ms-click="click('bbb')">{{bbb}}</div>
- <div ms-click="click('$ccc')">{{$ccc}}</div>
- <div ms-click="click('ddd')">{{ddd}}</div>
- </body>
- </html>
注意,$watch回调里是用ecma262 v6 提供的新API Object.is做新旧值比较,它的功能与=== 差不多,但能对付NaN这个自己也不等于自己的怪胎。另,一个对象字面量即便外形看上去一致,也是一个新对象,不会等于原来的。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="avalon.js" ></script>
- <script>
- var model = avalon.define({
- $id: "test",
- aaa: "1111",
- nan: NaN,
- object: {a: 1, b: 2},
- array: [1, 2],
- ddd: "1",
- $skipArray: ["ddd"],
- click: function(a) {
- if (a == "object") {
- model[a] = {a: 1, b: 2}
- } else if (a == "array") {
- model[a] = [1, 2]
- } else if (a == "nan") {
- model[a] = NaN
- } else {
- model[a] = "1111"
- }
- }
- })
- model.$watch("$all", function(name, a, b) {
- console.log(name, a, b)
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('aaa')">{{aaa}}</div>
- <div ms-click="click('nan')">{{nan}}</div>
- <div ms-click="click('object')">
- <div ms-repeat='object'>{{$key}}</div>
- </div>
- <div ms-click="click('array')">
- <div ms-repeat='array'>{{el}}</div>
- </div>
- <div ms-click="click('ddd')">{{ddd}}</div>
- </body>
- </html>
对于数组,我们只能监听数组长度的变化,不能监听其内部是否发生变化。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="../avalon.js" ></script>
- <script>
- var model = avalon.define({
- $id: "test",
- array: [1, 2],
- click: function(a) {
- model.array.push(new Date - 0)
- }
- })
- model.array.$watch("length", function( a, b) {
- console.log(a, b)
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('array')">
- <div ms-repeat='array'>{{el}}</div>
- </div>
- </body>
- </html>
如果你一定要监听数组每个元素的变化,可以使用1.3.4新添加的tick函数,这是一个心跳检测,只要函数返回false就会从检测列队中移除。由于是每30ms检测一次,非常耗性能,因此不用时记得移除。
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width">
- <script src="../avalon.js" ></script>
- <script>
- var ret
- var model = avalon.define({
- $id: "test",
- array: [1, 2, 3, 4, 5, 6, 7, 8],
- stop: function(){
- ret = false
- },
- click: function(a) {
- var index = Math.floor(Math.random() * 8)
- model.array.set(index, new Date - 0)
- }
- })
- var old = model.$model.array.concat()
- avalon.tick(function() {
- console.log("tick...")
- var now = model.$model.array.concat()
- for (var i = 0, n = now.length; i < n; i++) {
- if (now[i] !== old[i]) {
- console.log("第" + i + "个元素发生变化: " + old[i] + " --> " + now[i])
- }
- }
- old = now
- return ret
- })
- </script>
- <style>
- .ms-hover div:hover{
- background:yellowgreen;
- }
- </style>
- </head>
- <body ms-controller="test" class='ms-hover'>
- <div ms-click="click('array')">
- <div ms-repeat='array'>{{el}}</div>
- </div>
- <button type='button' ms-click='stop'>移除此监听器</button>
- </body>
- </html>
稍微说一下 $unwatch的用法,这个不太常用。如果它传入两个参数,第一个为属性名,第二个为回调,那么就会移除此用户,如果只传入此属性名,则移除此属性的所有监听函数。如果什么也不传,那么就会临时中断此ViewModel的属性监听功能,所有$watch回调都不会触发。想恢复也很简单,调用$watch方法,也是什么也不传。
我们最后看一下1.3.2新增的跨模块通信功能,我们通过在$fire的第一个参数一些前缀,就能触发其他模块的属性回调。它们分别是”up!”, “down!”, “all!”。上与下是根据当前ViewModel所在ms-controller元素在DOM树位置决定的。
- up!xxx, 向上冒泡
- down!xxx, 向下捕获
- all!xxx, 全局广播
- <!DOCTYPE html>
- <html>
- <head>
- <title>by 司徒正美</title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <script src="avalon.js"></script>
- <script>
- avalon.define("ancestor", function(vm) {
- vm.aaa = '1111111111'
- vm.$watch("aaa", function(v) {
- avalon.log(v)
- avalon.log("ancestor.aaa事件被触发了")
- })
- vm.click = function() {
- avalon.log("向下广播")
- vm.$fire("down!aaa", "capture")
- }
- })
- avalon.define("parent", function(vm) {
- vm.text = "222222222"
- vm.aaa = '3333333333'
- vm.$watch("aaa", function(v) {
- avalon.log(v)
- avalon.log("parent.aaa事件被触发了")
- })
- vm.click = function() {
- console.log("全局扩播")
- vm.$fire("all!aaa", "broadcast")
- }
- })
- avalon.define("son", function(vm) {
- vm.$watch("aaa", function(v) {
- avalon.log(v)
- avalon.log("son.aaa事件被触发了")
- })
- vm.click = function() {
- console.log("向上冒泡")
- vm.$fire("up!aaa", "bubble")
- }
- })
- </script>
- </head>
- <body class="ms-controller" ms-controller="ancestor">
- <h3>avalon vm.$fire的升级版 </h3>
- <button type="button" ms-click="click">
- capture
- </button>
- <div ms-controller="parent">
- <button type="button" ms-click="click">broadcast</button>
- <div ms-controller="son">
- <button type="button" ms-click="click">
- bubble
- </button>
- </div>
- </div>
- </body>
- </html>
迷你MVVM框架 avalonjs 学习教程15、属性监听与模块通信的更多相关文章
- 迷你MVVM框架 avalonjs 学习教程3、绑定属性与扫描机制
在MVVM框架中,你都会看到页面定了许多奇怪的属性,比如knockout的data-☆,angular的ng-☆,avalon的ms-☆,此外还有一些只写文本节点上的双花括号,它们统称为指令.ms-☆ ...
- 迷你MVVM框架 avalonjs 学习教程19、avalon历史回顾
avalon最早发布于2012.09.15,当时还只是mass Framework的一个模块,当时为了解决视图与JS代码的分耦,参考knockout开发出来. 它的依赖收集机制,视图扫描,绑定的命名d ...
- 迷你MVVM框架 avalonjs 学习教程20、路由系统
SPA的成功离开不这三个东西,分层架构,路由系统,储存系统.分层架构是我们组织复杂代码的关键,这里特指MVVM的avalon:路由系统是将多个页面压缩在一个页面的关键:储存系统特指本地储存,是安全保存 ...
- 迷你MVVM框架 avalonjs 学习教程18、一步步做一个todoMVC
大凡出名的MVC,MVVM框架都有todo例子,我们也搞一下看看avalon是否这么便宜. 我们先从react的todo例子中扒一下HTML与CSS用用. <!doctype html> ...
- 迷你MVVM框架 avalonjs 学习教程2、模块化、ViewModel、作用域
一个项目是由许多人分工写的,因此必须要合理地拆散,于是有了模块化.体现在工作上,PM通常它这为某某版块,某某频道,某某页面.某一个模块,必须是包含其固有的数据,样式,HTML与处理逻辑.在jQuery ...
- 迷你MVVM框架 avalonjs 学习教程1、引入avalon
avalon是国内最强大的MVVM框架,没有之一,虽然淘宝KISSY团队也搞了两个MVVM框架,但都无疾而终.其他的MVVM框架都没几个.也只有外国人与像我这样闲的架构师才有时间钻研这东西.我很早之前 ...
- 迷你MVVM框架 avalonjs 学习教程21、双向绑定链
avalon的双向绑定机制,是通过一条依赖链实现.此依赖链最底层是监控属性.监控数组,中层是计算属性.监控函数,再上点是求值函数,最上层是视图刷新函数. 所谓计算属性,监控属性,监控函数属性,我们改变 ...
- 迷你MVVM框架 avalonjs 学习教程12、数据联动
在许多表单应用,我们经常遇到点击一个复选框(或下拉框)会引发旁边的复选框(或下拉框)发生改变,这种联动效果用avalon来做是非常简单的.在avalon里,存在各种绑定回调与$watch回调,完全满足 ...
- 迷你MVVM框架 avalonjs 学习教程8、属性操作
属性操作是DOM操作很大的一块,它包括类名操作,表单元素的value属性操作,元素固有属性的管理,元素自定义属性的管理,某些元素的一些布尔属性的操作.大多数情况下,元素属性的值是字符串类型,我们称之为 ...
随机推荐
- 各JAVA开发框架版本及对应信息
日期:2017.05.22 当前最新 release 版本情况: 框架 最新GA(General Availability)版本 spring 4.3.8 spring boot 1.5.3 myba ...
- json包含单双引号问题解决方案
解决方案:在后台处理 JSONArray.fromObject(list).toString() 转自明明如月小角落: 效果DEMO: JsonQuotesUtil.js /** * 解决json传输 ...
- 【jemter】HTTP请求参数化
HTTP请求参数化:就是把URL的参数项做参数化处理 我们现在要对子猴博客来进行一番压力测试,压力测试对象为随机的几个网页链接,这几个链接是写在一个文本文件中的,在压力测试的时候会随机读取. 1. ...
- pbuf类型和应用
下面的讨论仅限于RAW API. 按存储方式分类 1. PBUF_RAM 从一般性的Heap中分配.可用空间大小受MEM_SIZE宏控制.可看作一般意义上的动态内存. 用途: a) 将应用层中的待发送 ...
- BASIC-19_蓝桥杯_完美的代价
思路(贪心): 1.两边往中间逼近,步数少; 2.单个字符出现时只考虑移动到中间的步数,不做移动,因为这是最后进行,不影响结果; 示例代码: #include <stdio.h>#defi ...
- Date类型之继承方法
ECMAScript中的Date类型是在早期Java中的java.util.Date类型基础上构建的.为此,Date类型使用自UTC(国际协调时间)1970年1月1日午夜零时开始经过的毫秒数来保存日期 ...
- Kibana安装及使用
1.Kibana介绍Kibana是一个基于浏览器页面的Elasticsearch前端展示工具.Kibana全部使用HTML语言和Javascript编写的. 2.安装配置Kibana下载地址:http ...
- linux下一个网卡配置多个ip【虚拟ip】
Linux下配置网卡ip别名何谓ip别名?用windows的话说,就是为一个网卡配置多个ip.什么场合增加ip别名能派上用场?布网需要.多ip访问测试.特定软件对多ip的需要...and so on. ...
- [UE4]添加蒙太奇动画
选择蒙太奇所使用的骨骼
- SQL语句嵌套if
在存储过程中我要实现一个IF的嵌套语句查询,类似与 if() { if() { ...... } else { .... ...