迷你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属性操作,元素固有属性的管理,元素自定义属性的管理,某些元素的一些布尔属性的操作.大多数情况下,元素属性的值是字符串类型,我们称之为 ...
随机推荐
- C#如何使用VS2010与SQL2008建立链接及初步调用(转)
关于VS2010与SQL2008建立链接及初步调用问题,网上参考的资料很多,我写这个博客,并非是做重复工作,也不是做搬运工.本文将以一种初学者的角度,去完成从数据库建立,到VS2010与SQL中的数据 ...
- Git密钥生成步骤SSH Key
顺便推荐下自己的网站: 一个php后台极速开发框架 https://www.lotusadmin.top/ 一个有趣的网站 https://www.waytomilky.com/ Git是分布式的代码 ...
- C#利用zxing.net操作二维码和条形码
下载地址:http://zxingnet.codeplex.com/ zxing.net是.net平台下编解条形码和二维码的工具,使用非常方便. 首先下载二进制dll文件,引入工程: 代码: usin ...
- java 关于Java中静态代码块以及构造函数的执行先后顺序
先转个链接 http://blog.csdn.net/wangbaokangfei/article/details/7757320 另外补充一下.静态方法,只执行一次就自动在内存中存在,再次实例化此 ...
- 【Spring学习笔记-MVC-17】Spring MVC之拦截器
作者:ssslinppp 1. 拦截器简介及应用场景 2. 拦截器接口及拦截器适配器 3. 运行流程图 正常运行 中断流程 4. 程序实例 控制层: @Controller @Reques ...
- 5.验证用户名是否已经被注册:AJAXC请求
首先在 web.xml 文件中添加配置信息 <!-- 配置全局的字符集 --> <context-param> <param-name>encode</par ...
- ASP.NET Web Pages:简介
ylbtech-.Net-ASP.NET Web Pages:简介 ASP.NET 是一个使用 HTML.CSS.JavaScript 和服务器脚本创建网页和网站的开发框架. ASP.NET 支持三种 ...
- http接口测试工具——RESTClient
摘要: RESTClient是用java Swing编写的基于http协议的接口测试工具,工具比较灵巧,便于做接口的调试,源码在官网上可以下到,感兴趣的可以研究一下 WizTools.org REST ...
- linux上很方便的上传下载文件工具rz和sz使用介绍
简单说就是,可以很方便地用这两个sz/rz工具,实现Linux下和Windows之间的文件传输(发送和接收),速度大概为10KB/s,适合中小文件.rz/sz 通过Zmodem协议传输数据 一般来 ...
- matlab批量修改图片大小
转自:http://blog.csdn.net/cike0cop/article/details/53087995 %author:coplin %time:2016-10-10 %function: ...