1.1 1.2 1.2.1 1.2.2 1.2.3 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 Table of Contents 扉⻚ 介绍 who vm 虚拟DOM 指令 插值表达式 ms-skip ms-controller ms-important ms-attr ms-css ms-text ms-html ms-class ms-active ms-hover ms-if ms-visible ms-for ms-on ms-duplex ms-rules ms-validate 11.3.19 1.3.20 1.3.21 1.4 1.5 1.6 1.7 1.8 1.9 1.10 1.11 1.12 1.13 ms-effect ms-widget ⾃定义标签 组件 过滤器 类型转换器 表单验证 配置 移动端⽀持 常⻅问题 与jQuery混⽤ API 更新⽇志 2avalon 2 迷你 、 易⽤ 、 ⾼性能 的前端MVVM框架 测试⻚⾯avalon仓库perf⽬录下的 index.html , index.*.html ⽂件 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-27 21:35:06 扉⻚ 3简介 avalon2是⼀款基于虚拟DOM与属性劫持的 迷你、 易⽤、 ⾼性能 的 前端 MVVM框架, 适⽤于各种场景, 兼容各种古⽼刁钻浏览器, 吸收最新的技术成 果, 能迅速堆砌组件与应⽤。 谁在使⽤avalon 使⽤⽅式 avalon2: https://github.com/RubyLouvre/avalon/tree/2.1.2/dist CDN: http://www.bootcdn.cn/avalon.js/ 注意 , 不要使⽤avalon2.0s,avalon2.0b1,avalon2.0b2,那是很早期的 beta版本 npm install avalon2 avalon2是使⽤⼀份源码编译成N个版本: avalon ⽀持IE6+及古⽼的W3C浏览器(判定标准是 这些浏览器是否⽀持VBScript, __defineSetter__, __defineGetter_ _) avalon.modern ⽀持IE10+及较新的W3C浏览器(判定标准是 这些浏览器是否⽀持Object.defineProperty, addEventListener) avalon.next ⽀持IE12+(edge)及chrome49, firefox49(判定标准是 这些浏览器是否⽀持Proxy, document.registerElement) 学习资料 介绍 4avalon2-seed 这是⼀个avalon项⽬的框架,可以将它作为avalon项⽬的⼯程 初始化⽬录配置。 1.4的⼊⻔教程 1.4的仓库地 1.4的另⼀个更漂亮的教程 1.5的⼊⻔教程 1.5的仓库地址 1.×的视频教程 1.*的官⽹地址 前端乱炖⽹站上的avalon1.5学习教程 segementfault⽹站上的avalon2学习教程 avalon论坛 QQ学习群: 314247255 电⼦书下载:avalon cookbook ⼊⻔例⼦ 介绍 5 first example

Hello,{{@name}}!

  • {{$index}}--{{el}}
这⾥⾯涉及⼀些知识点 1. vm,使⽤avalon.define⽅法⽣成,必须带$id属性 2. 指令,以ms-开头的属性及双花括号的插值表达式 3. 圈定作⽤域,使⽤ms-controller告诉框架,只处理这个范围内的标签 4. 引导符,使⽤ @ 或 ## 来告诉框架这些变量是来⾃vm的 介绍 65. ⾃动扫描机制 avalon2.1.15后还可以使⽤ :xxxx 短指令.

Hello,{{@name}}!

  • {{$index}}--{{el}}
avalon起源 avalon 是⼀个简单易⽤迷你的MVVM框架,它最早发布于2012.09.15, 为解 决同⼀业务逻辑存在各种视图呈现⽽开发出来的。 事实上,这问题其实也可 以简单地利⽤⼀般的前端模板加jQuery 事件委托 搞定, 但随着业务的膨 胀, 代码就充满了各种选择器与事件回调,难以维护。 因此彻底的将业务与 逻辑分离,就只能求助于架构。 最初想到的是MVC,尝试过backbone,但 代码不降反升,很偶尔的机会,碰上微软的WPF, 优雅的MVVM架构⽴⻢吸 引住我,我觉得这就是我⼀直寻找的解决之道。 avalon将所有前端代码彻底分成两部分,视图的处理通过绑定实现(angular 有个更炫酷的名词叫指令), 业务逻辑则集中在⼀个个叫VM的对象中处 理。我们只要操作VM的数据,它就⾃然⽽然地神奇地同步到视图。 显然所 有神秘都有其内幕,C#是通过⼀种叫访问器属性的语句实现,那么JS也有对 应的东⻄。 感谢上帝,IE8最早引⼊这东⻄( Object.defineProperty ),可 惜有BUG,但带动了其他浏览器实现它, IE9+便能安全使⽤它。 对于⽼式 IE,我找了好久,实在没有办法,使⽤VBScript实现了。 Object.defineProperty或VBS的作⽤是将对象的某⼀个属性,转换⼀个setter 与getter, 我们只要劫持这两个⽅法,通过Pub/Sub模式就能偷偷操作视 图。为了纪念WPF的指引, 我将此项⽬以WPF最初的开发代号avalon来命 介绍 7名。 它真的能让前端⼈员脱离DOM的苦海,来到数据的乐园中! avalon的所有指令都是以 ms-* 命名,ms是⽤纪念我之前的⼀个框架 mass Framework ! Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-27 16:46:32 介绍 8谁在使⽤avalon 欢迎各位使⽤者到QQ群找作者提交你们公司的LOGO与链接 who 9who 10who 11who 12who 13Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-24 23:02:20 who 14vm avalon的所有操作都是围绕vm进⾏。vm,亦即view model,视图模型。只要 我将⼀个JS对象添加⼀个$id属性,再放到avalon.define⽅法⾥⾯,就能得到 ⼀个vm。 var vm = avalon.define({ $id: "start", name: "test" }) vm是⼀种利⽤Proxy或 Object.defineProperties或VBScript创建的特殊对象。 ⾥⾯以$带头的属性或放到$skipArray,都转换为访问器属性,也就是其他语 ⾔的setter, getter。因此如果这个属性最初没有定义,那么它就不会转换为访 问器属性,修改该属性,就不会刷新视图。 avalon定义了的vm,都可以在avalon.vmodels中查看到。我们可以在chrome 控制台下看⼀下刚才的start vm的构造。 vm 15平时⽽⾔,vm是⼀种⽐较重型的对象。从占⽤内存⻆度来划分,浏览器中的 四种对象排⾏如下: 1. 超轻量 Object.create(null) 2. 轻量 ⼀般的对象 {} 3. 重量 带有访问器属性的对象, avalon VM对象 4. 超重量 各种节点或window对象 内部属性 VM中以$开头的属性都是框架保留使⽤的特殊属性,⼤家为数据起名字时要⼩ ⼼避开 这些以$开头的属性,⽬前除了$id, $events, $watch, $fire, $model⽐较稳定外, 其他系统属性在不同版本存在增删的情况. 1. $id, vm的名字 2. $watch, ⽤于添加监听函数 vm 163. $fire, ⽤于触发监听函数 4. $events, ⽤于储存监听函数 5. $model, 返回⼀个纯净的JS对象 6. $hashcode, 2.0新增,由于$id⽆法保证唯⼀性,使⽤这个作为UUID 7. $accessors, ⽤于放置访问器的定义,出现在兼容⽚的avalon VM上. 8. $render, 2.0新增, ⽤于⽣成虚拟DOM树. 9. $element, 2.0新增, 当我们⽤ms-controller, ms-important指定⼀个VM的 作⽤域,对应元素节点会放到这个属性上. 10. $track, 1.5新增, ⽤于实现hasOwnProperty⽅法. VM的hasOwnProperty 会对系统属性返回false 另外,avalon不允许在VM定义之后,再追加新属性与⽅法,⽐如下⾯的⽅式 是错误的: var vm = avalon.define({ $id: "test", test1: "点击测试按钮没反应 绑定失败" }) vm.one = function () { //不能再追加此⽅法 vm.test1 = "绑定成功" } 但我们可以通过以下⽅式,实现添加⼦属性。 vm 17var vm = avalon.define({ $id: "test", placehoder: {} }); setTimeout(function () { vm.placehoder = {//我们必须要通过 = ,直接添加⼀个对象来添加⼦属性 , 不能 aaa: 1, //vm.placehoder.aaa =1; vm.placehoder.bbb = 2这样分 散地添加⼦属性 bbb: 2 } }, 1000) VM中的数据更新,只能通过 = 赋值⽅式实现。但要注意在IE6-8,由于VM是 ⼀个VBScript对象,为VM添加新属性会抛错, 因此我们想批量更新属性要 时格外⼩⼼了,需要⽤hasOwnProperty进⾏过滤。 注意在IE6-8 下,err是VBscript的关键字,VM中存在这个字段,就会将VM中 的其他数组变成字符串,详⻅这⾥ 为了性能起⻅,请确保你的对象结构⾜够扁平,套嵌层次不能太深,⾥ ⾯的数组不能太⻓。 监控属性 在VM中,改变它们会引起视图改变的属性。如果⼀个属性是$开头, 或在定义 时放在$skipArray数组中,或是函数或节点元素, 它们都不会转换成监控属性. 此外, 改变监控属性的值还会触发对应的$watch监听回调. 监控数组 操作此数组的⽅法会同步视图的特殊数组,它是由VM中的数组⾃动转换⽽ 来。⽅便与ms-repeat, ms-each配合使⽤, 能批量同步⼀⼤堆DOM节点。 vm 18监控数组的⽅法与普通数组没什么不同,它只是被重写了某⼀部分⽅法,如 pop, shift, unshift, push, splice,sort, revert。其次添加了四个移除⽅法, remove, removeAt, removeAll, clear, 及ensure,pushArray,set⽅法。 1. pushArray(el), 要求传⼊⼀数组,然后将它⾥⾯的元素全部添加到当前数 组的末端。 2. remove(el), 要求传⼊⼀元素,通过全等于⽐较进⾏移除。 3. removeAt(index), 要求传⼊⼀数字,会移除对应位置的元素。 4. removeAll(arrayOrFunction), 有三种⽤法,如果是⼀个函数,则过滤⽐ 较后得到真值的元素, 如果是⼀数组,则将此数组中与原数组相等于的 元素全部移除;如果没有任何参数,则全部清空。 5. clear(),相当于removeAll()的第三种⽅法,清空数组的所有元素。由于 需要同步视图的缘故,不能通过vm.array.length = 0的⽅法来清空元素。 6. ensure(el),只有当数组不存在此元素时,只添加此元素。 7. set(index, el),⽤于更新某⼀索引位置中的元素,因为简单数组元素的 数组,是不会转换它的元素。 注意,修改某个数组元素必须使⽤set⽅法. 如果是修改 对象数组 的某个 元素的属性可以⽤ vm.array[1].prop = 'newValue'
{{el}}
⾮监控属性 vm 19这包括框架添加的$id, $events, $model属性, $fire, $watch, $render⽅法, 及⽤户⾃⼰设置的以$开头的属性,放在$skipArray数组中的属性,值为函 数、各种DOM节点的属性, 总之,改变它们的值不会产⽣同步视图的效果。 $watch⽅法 在avalon早期是, 存在⼀个对象能mixin进每个VM,让VM具有$watch, $unwatch, $fire, $events等⽅法或属性. 这有点像jQuery的on, off, trigger⽅ 法,只是为了更造近angular等MVVM框架,名字起成这样. 此⽅法是⽤于监听vm中的对象的属性变化. 换⾔之,它不能监听函数,不能监听简单数组的元素变化(如[1,2,3]变成 [4,2,3]) 它能监听⼦级对象的属性变化,能监听对象数组的属性变化(如[{a:1,a:2}]变成 [{a:'change',a:2}]), 还有数组的⻓度属性变化 此外从1.5起,⽀持""通配符,解决对数组元素,⼦属性的监听.注意,号只能出现⼀ 次. 下⾯是$watch⽅法的的七种⽤法 var vm = avalon.define({ $id: "test", array: [1, 2, 3], d: 888, arr: [{ a: 1 }, { a: 2 }, { a: 3 }], obj: { a: 1, b: 2 vm 20 }, a: { b: { c: { d: 33 } } } }) var expect = function (a) { return { to: { be: function (b) { console.log(a == b) } } } } vm.$watch("array.length", function (a, b, name) { console.log('第⼀组 数组⻓度', name) }) vm.$watch("arr.*.a", function (a, b, name) { expect(a).to.be(99) expect(b).to.be(1) console.log('第⼆组 数组元素属性(模糊匹配, 不知道哪个元素变化)', na me) }) vm.$watch("obj.a", function (a, b, name) { expect(a).to.be(111) expect(b).to.be(1) console.log('第三组 属性的属性', name) }) vm.$watch("obj.*", function (a, b, name) { expect(a).to.be(111) expect(b).to.be(1) vm 21 console.log('第四组 属性的属性(模糊匹配)', name) }) vm.$watch("a.b.c.d", function (a, b, name) { expect(a).to.be(88) expect(b).to.be(33) console.log('第五组 属性的属性的属性', name) }) vm.$watch("a.*.c.d", function (a, b, name) { expect(a).to.be(88) expect(b).to.be(33) console.log('第六组 属性的属性的属性(模糊匹配)', name) }) vm.$watch("*", function (a, b, name) { expect(a).to.be(999) expect(b).to.be(888) console.log('第七组 第⼀层对象的任意属性(模糊匹配)', name) }) setTimeout(function () { vm.array.set(1, 6) vm.array.push(99) vm.arr[0].a = 99 vm.obj.a = 111 vm.a.b.c.d = 88 vm.d = 999 }, 100) $watch会返回⼀个函数,⽤于解除监听: var unwatch = vm.$watch("array.*", function (a, b) { expect(a).to.be(6) expect(b).to.be(2) }) unwatch() //移除当前$watch回调 ` vm 22监听函数有三个参数, 第⼀个是新值, 第⼆个是旧值, 第三个是发⽣变动 的属性的名字。 $watch⽅法供与其他操作DOM的库⼀起使⽤的,如富⽂本编辑器什么. 在 $watch回调⾥更新VM⾃身的属性是⾮常危险的事,很容易引发死循环 $fire⽅法 $fire可以传多个参数, 第⼀个参数为事件名,或者说是VM上已存在的属性 名, 当VM中对应的属性发⽣变化时,框架内部就调⽤$fire⽅法, 依次传⼊ 属性名,当前属性值,过去属性值。 数据模型 是指VM中的$model属性,它是⼀个纯净的javascript对象,去掉$id, $watch 等⽅法或属性,可以直接通过$.ajax提交给后端,当然我们 还可以通过 JSON.parse(JSON.stringify(vm.$model))⼲掉⾥⾯的所有函数。 注意,不要修改$model,你只能通过VM来改动$model,否则在1.5 中,$model是只读的,每次都是返回⼀个全新的对象给你 你改了也没有 ⽤! vm是如何作⽤视图 我们需要在⻚⾯上,使⽤ms-controller或ms-important来圈定每个vm的作⽤ 范围。当⻚⾯domReady时,vm就将⾃动将其⾥⾯的数据替换到各种指令中 去,实现视图刷新效果。 注意⼀个vm只能在⻚⾯上使⽤⼀次。即⻚⾯上不能重复出现相同的值 的ms-controller。
{{@aaa}}
{{@aaa}}
{{@aaa}}
vm 23由于test这个vm拥有⼀个叫$element的属性,它是保存其关联的元素节点, 如果定义了多少个,那么它会保留最后的那个DIV。以后它的属性变化,只 会作⽤最后的那个DIV。 vm的运作原理 avalon之所以使⽤Proxy, Object.defineProperty或VBScript来构造vm,那是 因为它们创建出来的对象有⼀种⾃省机制,能让我们得知vm正在操作或访问 了我们的对象。 对于Object.defineProperty或VBScript,主要是靠将普通属性变成访问器属 性。访问器属性内部是拥有两个⽅法,setter与getter。当⽤户读取对象的属 性时,就将调⽤其getter⽅法,当⽤户为此属性赋值时,就会调⽤setter⽅ 法。因此,我们就不需要像angular那样,使⽤脏检测,就得知对象被修改了 某些属性了。并且能准确得知那些属性,及时地同步视图的相应区域,实现 最⼩化刷新视图。 对于Proxy(智能代理),这最早发迹于firefox4,现在许多新浏览器都⽀持,它 能监听外部⽤户对它的14种,⽐如说读写属性,调⽤⽅法,删除旧属性,添 加新属性,被for in循环, 被in关键字进⾏存在性检测, 被new……因此之前 所说的,不能监听没预先定义的属性, 这个难题被Proxy搞定了。 当我们得知vm的属性发⽣变化了,如何更新视图呢?在avalon2中,这个是 由虚拟DOM来处理。 虚拟DOM⽐较复杂,⼤家看不懂可以略过。 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-19 17:55:51 vm 24虚拟DOM avaon会在DOMReady对.ms-controller节点进⾏outerHTML操作 之前是直接 ⽤outerHTML,但后来发现outerHTML在各个浏览器下差异性太⼤了. IE6-7会 对colgroup, dd, dt, li, options, p, td, tfoot, th, thead, tr元素⾃闭合 让我的 htmlPaser跪掉 于是写了htmlfy,⼿动取每个元素nodeName, attrName, attrValue, nodeValue来构建outerHTML 第2阶段,将这个字符串进⾏parser,转换为虚拟DOM 这个阶段对input/textarea 元素补上type属性, ms-* ⾃定义元素补上ms-widget属性, 对table元素补上 tbody, 在ms-for指令的元素两旁加上 , 占 位符, 并将它们的之间的元素放到⼀个数组中(表明它们是循环区域) 并去掉所 有只有空⽩的⽂本节点 第3个阶段,优化,对拥有 ms-* 属性的虚拟DOM添加dynamic属性 表明它以后 要保持其对应的真实节点,并对没有 ms-* 属性的元素添加skipAttrs属性,表明 以后不需要遍历其属性。 如果它的⼦孙没有 ms-* 或插值表达式或ms-⾃定 义元素,那么还加上skipContent,表明以后不要遍历其孩⼦. 这三个属性,dynamic⽤于节点对⻬算法,skipAttrs与skipContent⽤于diff算法 第4个阶段, 应⽤节点对⻬算法, 将真实DOM中⽆⽤的空⽩节点移除,并插⼊占 位符, 并将需要刷新的元素保持在以应的拥有dynamic属性的虚拟DOM中 第5个阶段,放进render⽅法中,render⽅法⾥⾯再调parseView,parseView会调 每个指令的parse⽅法 将虚拟DOM树转换为⼀个$render⽅法 第6个阶段,执⾏$render⽅法,⽣成新的虚拟DOM,与最早的那个虚拟DOM树 diff,⼀边diff⼀边更新真实DOM. 以后VM的属性发⽣变动,就直接执⾏第6个阶段. Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-08 17:03:14 虚拟DOM 25虚拟DOM 26avalon的指令是⼀个⾮常重要的东⻄,它⽤来引⼊⼀些新的HTML语法, 使元素 拥有特定的⾏为。 举例来说,静态的HTML不知道如何来创建和展现⼀个⽇ 期选择器控件。 让HTML能识别这个语法,我们需要使⽤指令。 指令通过某 种⽅法来创建⼀个能够⽀持⽇期选择的元素。 指令⼀共拥有3种形式: 指令 avalon的指令是⼀个⾮常重要的东⻄,它⽤来引⼊⼀些新的HTML语法, 使元素 拥有特定的⾏为。 举例来说,静态的HTML不知道如何来创建和展现⼀个⽇ 期选择器控件。 让HTML能识别这个语法,我们需要使⽤指令。 指令通过某 种⽅法来创建⼀个能够⽀持⽇期选择的元素。 指令⼀共拥有3种形式 1. 插值表达式 2. ⾃定义标签 3. 绑定属性 其中 绑定属性 的种类是最多的,它们都位置于元素节点中,以ms-开头或以: 开头(avalon2.1.7新增) 绑定属性的属性名是以-分成⼏段 其中第⼆个就是指令的名字, 如ms-css, ms- attr, ms-html, ms-text, ms-on都是来源于jQuery同名⽅法名, 简单好记.

{{@name}}

指令 27指令 28与1.4,1.5相⽐, 2.0是移除了ms-repeat, ms-each, ms-with, ms-include, ms-include-src,ms-data, ms-scan, ms-if-loop指令. Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-14 16:55:21 指令 29插值表达式 位于⽂本节点中的双重花括号,当然这个可以配置.此指令其中⽂本ms-text指 令的简单形式.

{{@aaa}}{{@bbb}} 这个性能差些

{{@aaa+@bbb}} 这个性能好些

{{@aaa+@bbb | uppercase}} 选择器必须放在表达值的后端

插值表达式⼀般与带格式化功能的过滤器⼀起使⽤. Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:25:33 插值表达式 30skip绑定 让avalon的扫描引擎跳过某⼀部分区域, ⽅便能原样输出 合理使⽤ms-skip能⼤⼤提⾼性能
{{@aaa}}
{{@aaa}}
Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:59:00 ms-skip 31controller绑定 这个指令是⽤于圈定某个VM的作⽤域范围(换⾔之,这个元素的outerHTML会 被扫描编译,所有ms-*及双花括号替换成vm中的内容),ms-controller的属性值 只能是某个VM的$id ms-controller的元素节点下⾯的其他节点也可以使⽤ms-controller 每个VM的$id可以在⻚⾯上出现⼀次, 因此不要在ms-for内使⽤ms-controller. 当我们在某个指令上⽤@aaa时,它会先从其最近的ms-controller元素上找, 找 不到再往其更上⽅的ms-controller元素 ms-controller 32
{{@name}} : {{@color}}
{{@name}} : {{@color}}
{{@name}} : {{@color}}
{{@name}} : {{@color}}
ms-controller 33当avalon的扫描引擎打描到ms-controller/ms-important所在元素时, 会尝试移 除ms-controller类名.因此基于此特性,我们可以在⾸⻚渲染⻚⾯时, 想挡住双 花括号乱码问题,可以尝试这样⼲(与avalon1有点不⼀样): .ms-controller{ visibility: hidden; } Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:59:50 ms-controller 34important绑定 这个指令是⽤于圈定某个VM的作⽤域范围(换⾔之,这个元素的outerHTML会 被扫描编译,所有 ms-* 及双花括号替换成vm中的内容),ms-important的属性 值只能是某个VM的$id ms-important的元素节点下⾯的其他节点也可以使⽤ms-controller或ms- important 与ms-controller不⼀同的是,当某个属性在ms-important的VM找不到时, 就不会所上寻找 不要在ms-for内使⽤ms-important. ms-important这特性有利协作开发,每个⼈的VM都不会影响其他⼈,并能⼤⼤ 提⾼性能 ms-important只能⽤于ms-controller的元素⾥⾯
Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-14 16:58:32 ms-important 35ms-important 36属性绑定 属性绑定⽤于为元素节点添加⼀组属性, 因此要求属性值为对象或数组形式. 数组最后也会合并成⼀个对象.然后取此对象的键名为属性名, 键值为属性值 为元素添加属性 如果键名如果为for, char这样的关键字,请务必在两边加上引号 如果键名如果带横杠,请务必转换为驼峰⻛格或两边加上引号 注意,不能在ms-attr中设置style属性

这样写是错的,需要⽤ms-css指令!!

示例: ms-attr 37 直接引⽤对象 使⽤对象字⾯量 直接引⽤数组 选择性添加多余属性或重写已有属性 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-27 23:00:19 ms-attr 38样式绑定 CSS绑定⽤于为元素节点添加⼀组样式, 因此要求属性值为对象或数组形式. 数组最后也会合并成⼀个对象.然后取此对象的键名为样式名, 键值为样式值 为元素添加样式 如果键名为表示⻓宽,字体⼤⼩这样的样式, 那么键值不需要加单位,会⾃ 动加上px 如果键名如果为float,请务必在两边加上引号 如果键名如果为font-size,请务必转换为驼峰⻛格或两边加上引号 直接引⽤对象 使⽤对象字⾯量 直接引⽤数组 选择性添加多余属性或重写已有属性 ms-css 39需要注意的是 设置背景图⽚是⽐较复杂 图⽚ 图⽚ Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 18:04:15 ms-css 40⽂本绑定 ⽂本绑定是最简单的绑定,它其实是双花括号插值表达式的⼀种形式 它要求VM对应的属性的类型为字符串, 数值及布尔, 如果是null, undefined将 会被转换为空字符串 不使⽤过滤器 使⽤过滤器 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-07 19:38:03 ms-text 41HTML绑定 HTML绑定类似于⽂本绑定,能将⼀个元素清空,填上你需要的内容 它要求VM对应的属性的类型为字符串 不使⽤过滤器 使⽤过滤器 我们可以通过ms-html异步加载⼤⽚内容。
Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:51:25 ms-html 42类名绑定 属性绑定⽤于为元素节点添加⼏个类名, 因此要求属性值为字符串,多个类名 以空格隔开; 为对象时,键名为类名,键值为布尔或01,为数组时,为字符串数组 直接引⽤字符串 直接引⽤对象 直接引⽤数组 使⽤对象字⾯量 选择性添加 类名 选择性添加类名 动态⽣成类名 ms-class 43Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:22:33 ms-class 44active绑定 为元素添加:active效果,当元素被点击时添加⼏个类名, ⿏标弹起后则⽴即移 除 直接引⽤字符串 直接引⽤对象 直接引⽤数组 使⽤对象字⾯量 选择 性添加类名 选择性添加类名 动态⽣成类名 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook ms-active 45该⽂件修订时间: 2016-07-25 17:21:45 ms-active 46hover绑定 ⽤于类实现:hover伪类的效果, 当⽤户⿏标移动元素上⽅时添加⼏个类名, ⿏ 标移⾛时将刚才的 类名移除 ⽤法类似于类名绑定,要求属性值为字符串,多个类名以空格隔开; 为对象时,键 名为类名,键值为布尔或01,为数组时,为字符串数组 ms-hover 47 直接引⽤字符串 直接引⽤对象 直接引⽤数组 使⽤对象字⾯量 选择性添加 类名 选择性添加类名 动态⽣成类名 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 17:23:05 ms-hover 48if绑定 通过属性值决定是否渲染⽬标元素, 为否时原位置上变成⼀个注释节点 avalon1.* 中ms-if-loop指令已经被废掉,请使⽤limitBy, selectBy, filterBy过滤器代替相应功能

绑定多个同种事件的例⼦: var count = 0 var model = avalon.define({ $id: "multi-click", str1: "1", str2: "2", str3: "3", click0: function() { model.str1 = "xxxxxxxxx" + (count++) }, click1: function() { model.str2 = "xxxxxxxxx" + (count++) }, click2: function() { model.str3 = "xxxxxxxxx" + (count++) } }) ms-on 62

⼀个元素绑定多个同种事件的回调
请点我
{{@str1}}
{{@str2}}
{{@str3}}
回调执⾏顺序的例⼦: avalon.define({ $id: "xxx", fn: function() { console.log("11111111") }, fn1: function() { console.log("2222222") }, fn2: function() { console.log("3333333") } })
ms-on 63avalon已经对ms-mouseenter, ms-mouseleave进⾏修复,可以在这⾥与这⾥ 了解这两个事件。 到chrome30时,所有浏览器都原⽣⽀持这两个事件。 avalon.define({ $id: "test", text: "", fn1: function (e) { this.text = e.target.className + " "+ e.type }, fn2: function (e) { this.text = e.target.className + " "+ e.type } }) .bbb{ background: #1ba9ba; width:200px; height: 200px; padding:20px; box-sizing:content-box; } .ccc{ background: #168795; width:160px; text-align: center; line-height: 160px; height: 160px; margin:20px; box-sizing:content-box; } ms-on 64
{{@text}}
最后是mousewheel事件的修改,主要问题是出现firefox上, 它死活也不愿意 ⽀持mousewheel,在avalon⾥是⽤DOMMouseScroll或wheel实现模拟的。 我们在事件对象通过wheelDelta属性是否为正数判定它在向上滚动。 avalon.define({ $id: "event4", text: "", callback: function(e) { this.text = e.wheelDelta + " " + e.type } })
{{@text}}
此外avalon还对input,animationend事件进⾏修复,⼤家也可以直接⽤ avalon.bind, avalon.fn.bind来绑定这些事件。但建议都⽤ms-on绑定来处 理。 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-08 19:45:32 ms-on 65ms-on 66双⼯绑定 双⼯绑定是MVVM框架中最强⼤的指令.react推崇单向数据流,没有双⼯绑定, 那么需要rudex等额外的库来实现相同的功能. 双⼯绑定只要⽤于表单元素上.或当⼀个div设置了contenteditable为true,也可 以⽤ms-duplex指令. 各个表单元素的⽤法 {{@aaa}} {{@bbb}} {{@ccc}} 上⾯有三个控件,text, password, textarea它们都是属于输⼊型控件, 只要每为 控件敲⼊⼀个字符, 后⾯的⽂本都会⽴即变化.那是因为它们默认是绑定 oninput事件,如果想控件全部输⼊好,失去焦点时 才同步,那么可以使 ⽤ change 过滤器 {{@aaa}} ms-duplex 67如果你是做智能提示, 控件是绑定了⼀个AJAX请求与后端不断交互, 使⽤ oninput事件会太频繁, 使⽤onchange事件会太迟钝,那么我们可以使 ⽤ debounce 过滤器 {{@aaa}} 300ms同步⼀次. 另外,可编辑元素的⽤法与过滤器与上⾯三种控件⼀样.

{{@aaa}}

这两个过滤器只能适⽤于上⾯的情况. 此外, 控件还有许多种, 像checkbox, radio,它们的同步机制也不⼀样. ms-duplex 68

radio: {{@aaa}}; checkbox:{{@bbb}}

checkbox与radio是⼀点击就会更新.radio要求在vm中为⼀个简单数据类型数 据,字符串,数字或布尔. ⽽checkbox则要求是⼀个数组.并且在最开始时,ms- duplex会令radio钩上其value值等vm属性的控件, checkbox则可以勾选多个. 如此⼀来,vm中的属性些总是等于radio与checkbox的属性值.但我们也可以让 vm的属性值等于此控件的勾选状态,这时需要⽤上 ms-duplex-checked 转换 器. ms-duplex 69

radio: {{@aaa}}; checkbox:{{@bbb}}

最后表单元素还有select控件,它根据其multiple属性分为单选下拉框与复选下 拉框, 其在vm中的值与radio,checkbox⼀样.即单选时,必须是⼀个简单数据类 型, 复选时为⼀个数组. 在最开始时, 当option元素的value值或innerText(不在 value值)与数据相同,它们就会被选上. ms-duplex 70控件 触发时机 数据 text,password,textarea及可 编辑元表 oninput,onchange, debounce 简单数据 radio,checkbox onclick 简单数据或 数组 select onchange 简单数据或 数组 数据转换 上⾯我们已经提到⼀个数据转换器ms-duplex-checked了.那只能⽤于 checkbox与radio. 为什么会有这种东⻄呢?因为⽆论我们原来的数据类型是什么,跑到表单中都 会变成字符串,然后我们通过事件取出来 它们也是字符串,不会主动变回 原来 的类型 .我们需要⼀种机制保持数据原来的类型,这就是数据转换器. avalon内置了4种过滤器 1. ms-duplex-string="@aaa" 2. ms-duplex-number="@aaa" 3. ms-duplex-boolean="@aaa" 4. ms-duplex-checked="@aaa" 前三个是将元素的value值转换成string, number, boolean(只有为'false'时转 换为false) 最后是根据当前元素(它只能是radio或checkbox)的checked属性值转换为 vm对应属性的值。 它们都是放在属性名上。当数据从元素节点往vmodel同步时,转换成预期的 数据。 ms-duplex 71数据格式化 ⼀般来说,数据格式化是由过滤器实现的,如 但这⾥有⼀个隐患,可能导致死循环, 因此建议放在事件回调中实现. {{@aaa}} {{@bbb}} 数据格式化是放在属性值时,以过滤器形式存在,如 ms-duplex='@aaa | uppercase' ms-duplex='@aaa | date('yyyy:MM:dd')' ms-duplex 72数据验证 这必须在所有表单元素的上⽅form元素加上ms-validate指令, 当前元素加上 ms-rules才会⽣效
详⻅ms-rules指令 同步后的回调 ms-duplex还有⼀个回调,data-duplex-changed,⽤于与事件绑定⼀样, 默 认第⼀个参数为事件对象。如果传⼊多个参数,那么使⽤$event为事件对象 占位。 示例 现在我们来⼀些实际的例⼦! 全选与⾮全选 ms-duplex 73var vm = avalon.define({ $id: "duplex1", data: [{checked: false}, {checked: false}, {checked: false}], allchecked: false, checkAll: function (e) { var checked = e.target.checked vm.data.forEach(function (el) { el.checked = checked }) }, checkOne: function (e) { var checked = e.target.checked if (checked === false) { vm.allchecked = false } else {//avalon已经为数组添加了ecma262v5的⼀些新⽅法 vm.allchecked = vm.data.every(function (el) { return el.checked }) } } })
全选
{{$index}}::{{el.checked}}
ms-duplex 74我们仔细分析其源码,allchecked是⽤来控制最上⾯的复选框的打勾情况, 数组中的checked是⽤来控制下⾯每个复选框的下勾情况。由于是使⽤ms- duplex,因此会监听⽤户⾏为, 当复选框的状态发⽣改变时,就会触发data- duplex-changed回调,将当前值传给回调。 但这⾥我们不需要⽤它的value 值,只⽤它的checked值。 最上⾯的复选框对应的回调是checkAll,它是⽤来更新数组的每个元素的 checked属性,因此⼀个forEach循环赋值就是。 下⾯的复选框对应的checkOne,它们是⽤来同步最上⾯的复选框,只要它们 有⼀个为false上⾯的复选框就不能打勾, 当它们被打勾了,它们就得循环整 个数组,检查是否所有元素都为true,是才给上⾯的checkall属性置为true。 现在我们学了循环指令,结合它来做⼀个表格看看。现在有了强⼤⽆⽐的 orderBy, limitBy, filterBy, selectBy。 我们做⾼性能的⼤表格是得⼼应⼿的! if (!Date.now) {//fix 旧式IE Date.now = function() { return new Date - 0; } } avalon.define({ $id: "duplex2", selected: "name", options: ["name", "size", "date"], trend: 1, data: [ {name: "aaa", size: 213, date: Date.now() + 20}, {name: "bbb", size: 4576, date:Date.now() - 4}, {name: "ccc", size: 563, date: Date.now() - 7}, {name: "eee", size: 3713, date: Date.now() + 9}, {name: "555", size: 389, date: Date.now() - 20} ] }) ms-duplex 75

本例⼦⽤于显示如何做⼀个简单的表格排序

{{el.name}} {{el.size}} {{el.date }}
我们再来⼀个⽂本域与下拉框的联动例⼦,它只⽤到ms-duplex,不过两个控 件都是绑定同⼀个属性。 avalon.define({ $id: "fruit", options: ["苹果", "⾹蕉", "桃⼦", "雪梨", "葡萄", "哈蜜⽠", "橙⼦", "⽕⻰果", "荔技", "⻩⽪"], selected: "桃⼦" }) ms-duplex 76

⽂本域与下拉框的联动

下拉框三级联动 ms-duplex 77var map = { "中国": ["江南四⼤才⼦", "初唐四杰", "战国四君⼦"], "⽇本": ["⽇本武将", "⽇本城堡", "幕府时代"], "欧美": ["三⼤骑⼠团", "三⼤魔幻⼩说", "七⼤奇迹"], "江南四⼤才⼦": ["祝枝⼭", "⽂征明", "唐伯⻁", "周⽂宾"], "初唐四杰": ["王勃", "杨炯", "卢照邻", "骆宾王"], "战国四君⼦": ["楚国春申君⻩歇", "⻬国孟尝君⽥⽂", "赵国平原君赵胜", "魏国信陵君魏⽆忌"], "⽇本武将": ["织⽥信⻓", "德川家康", "丰⾂秀吉"], "⽇本城堡": ["安⼟城", "熊本城", "⼤坂城", "姬路城"], "幕府时代": ["镰仓", "室町", "丰⾂", "江户"], "三⼤骑⼠团": ["圣殿骑⼠团", "医院骑⼠团", "条顿骑⼠团"], "三⼤魔幻⼩说": ["冰与⽕之歌", "时光之轮", "荆刺与⽩⻣之王国"], "七⼤奇迹": ["埃及胡夫⾦字塔", "奥林匹亚宙斯巨像", "阿尔忒弥斯⽉神殿" , "摩索拉斯陵墓", "亚历⼭⼤港灯塔", "巴⽐伦空中花园", "罗德岛太阳神巨像" ] } var vm = avalon.define({ $id: 'linkage', first: ["中国", "⽇本", "欧美"], second: map['⽇本'].concat(), third: map['⽇本武将'].concat(), firstSelected: "⽇本", secondSelected: "⽇本武将", thirdSelected: "织⽥信⻓" }) vm.$watch("firstSelected", function (a) { vm.second = map[a].concat() vm.secondSelected = vm.second[0] }) vm.$watch("secondSelected", function (a) { vm.third = map[a].concat() vm.thirdSelected = vm.third[0] }) ms-duplex 78

下拉框三级联动

这⾥的技巧在于使⽤$watch回调来同步下⼀级的数组与选中项。注意,使⽤ concat⽅法来复制数组。 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-25 20:27:42 ms-duplex 79验证规则绑定 avalon2砍掉了不少功能(如 ms-include , ms-data ),腾出空间加了其他 更有⽤的功能。 数据验证就是其中之⼀。现在avalon2内置的验证指令是参 考之前的oniui验证框架与jquery validation。 此指令只能⽤于添加ms-duplex指令的表单元素上。 avalon内置验证规则有 规则 描述 required(true) 必须输⼊的字段 email(true) 必须输⼊正确格式的电⼦邮件 url(true) 必须输⼊正确格式的⽹址 date(true或正 则) 必须输⼊正确格式的⽇期。默认是要求YYYY-MM-dd 这样的格式 number(true) 必须输⼊合法的数字(负数,⼩数) digits(true) 必须输⼊整数 pattern(正则 或true) 让输⼊数据匹配给定的正则,如果没有指定,那么会 到元素上找pattern属性转换成正则再匹配 equalto(ID 名) 输⼊值必须和 #id 元素的value 相同 maxlength: 5 输⼊⻓度最多是 5 的字符串(汉字算⼀个字符) minlength: 10 输⼊⻓度最⼩是 10 的字符串(汉字算⼀个字符) chs(true) 要求输⼊全部是中⽂ max:5 输⼊值不能⼤于 5 min:10 输⼊值不能⼩于 10 ms-rules 80这些验证规则要求使⽤ms-rules指令表示,要求为⼀个普通的JS对象。 此外要求验征框架能动起来,还必须在所有表单元素外包⼀个form元素,在 form元素上加ms-validate指令。 var vm = avalon.define({ $id: "validate1", aaa: "", bbb: '', ccc: '', validate: { onError: function (reasons) { reasons.forEach(function (reason) { console.log(reason.getMessage()) }) }, onValidateAll: function (reasons) { if (reasons.length) { console.log('有表单没有通过') } else { console.log('全部通过') } } } }) ms-rules 81

{{@aaa}}

因此,要运⾏起avalon2的内置验证框架,必须同时使⽤三个指令。ms- validate⽤于定义各种回调与全局的配置项(如什么时候进⾏验证)。ms- duplex⽤于将单个表单元素及相关信息组成⼀个Field对象,放到ms-validater 指令的fields数组中。ms-rules⽤于定义验证规则。如果验证规则不满⾜你, 你可以⾃⾏在avalon.validators对象上添加。 现在我们可以⼀下ms-validate的⽤法。其对应⼀个对象。 ms-rules 82配置项 描述 fields 框架⾃⾏添加,⽤户不⽤写。为⼀个数组, 放置ms-duplex⽣成的Field对象。 onSuccess 空函数,单个验证成功时触发,this指向被 验证元素this指向被验证元素,传参为⼀个 对象数组外加⼀个可能存在的事件对象。 onError 空函数,单个验证⽆论成功与否都触发, this与传参情况同上 onComplete 空函数,单个验证⽆论成功与否都触发, this与传参情况同上。 onValidateAll 空函数,整体验证后或调⽤了validateAll⽅ 法后触发;有了这东⻄你就不需要在form元 素上ms-on-submit="submitForm",直接将 提交逻辑写在onValidateAll回调上 onReset 空函数,表单元素获取焦点时触发,this指 向被验证元素,⼤家可以在这⾥清理 className、value validateInBlur true,在blur事件中进⾏验证,触发 onSuccess, onError, onComplete回调 validateInKeyup true, 在keyup事件中进⾏验证,触发 onSuccess, onError, onComplete回调。当 ⽤户在ms-duplex中使⽤change debounce 过滤器时会失效 validateAllInSubmit true,在submit事件中执⾏onValidateAll回 调 resetInFocus true,在focus事件中执⾏onReset回调 deduplicateInValidateAll false,在validateAll回调中对reason数组根 据元素节点进⾏去重 在上表还有⼀个没有提到的东⻄是如何显示错误信息,这个avalon不帮你处 理。但提示信息会帮你拼好,如果你没有写,直接⽤验证规则的message, 否则在元素上找data-message或data-required-message这样的属性。 最后给⼀个复杂的例⼦: ms-rules 83
验证完整的表单

ms-rules 86

主题 (⾄少选择两个) ms-rules 87

Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-07 23:36:54 ms-rules 88验证绑定 avalon2新引⼊的指令,只能⽤于form元素上,⽤于为表单添加验证功能。它 需要与ms-duplex, ms-rules指令⼀起配合使⽤。 此组件要依赖于Promise,显然Promise⽀持情况不太好,因此建议⼤ 家配合 es6 Promise库⼀起使⽤。 ms-validate的值应该对应⼀个对象,由于对象⽐较⼤,建议写在vm,像下⾯ 那样: ms-validate 89vm.validate = { onValidateAll: function(reasons){ //返回⼀个数组,如果⻓度为零说明没有错 }, onError: avalon.noop,//针对单个表单元素(使⽤了ms-duplex的input, select) onSuccess: avalon.noop,//针对单个表单元素 onComplete: avalon.noop,//针对单个表单元素 onReset: avalon.noop,//针对单个表单元素 validateInBlur: true, // {Boolean} true,在blur事件中进⾏验证,触 发onSuccess, onError, onComplete回调 validateInKeyup: true, // {Boolean} true,在keyup事件中进⾏验证, 触发onSuccess, onError, onComplete回调 validateAllInSubmit: true, // {Boolean} true,在submit事件中执⾏ onValidateAll回调 resetInFocus: true, // {Boolean} true,在focus事件中执⾏onReset 回调, deduplicateInValidateAll: false // {Boolean} false,在validateA ll回调中对reason数组根据元素节点进⾏去重 } onError,onSuccess,onComplete, onValidateAll的第⼀个参数都是reasons对 象,this指向被验证的元素,reason⾥⾯有你需要的各种东⻄. var reason = { element: elem, data: field.data, message: elem.getAttribute("data-" + ruleName + "-message") || elem.getAttribute("data-message") || hook.message, validateRule: ruleName, getMessage: getMessage } 有关它的详细⽤法建议看ms-rules指令 ms-validate 90Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-26 10:34:24 ms-validate 91动画绑定 ms-effect拥有这三种绑定形式:

fade为特效名

属性值为字⾯量,其中⼀个对象必须 包括is属性,这⽤于指定特效名

属性值为对象字⾯量, ⾥⾯拥有is 属性

属性值为vm的对象,⾥⾯拥有is属性

avalon2实际上没有实现完整的动画模块,它只是对现有的CSS3动画或 jquery animate再包装⼀层。 我们先说如何⽤CSS3为avalon实现动画效果。⾸先要使⽤avalon.effect注册 ⼀个特效。 avalon.effect(name, definition) 所有注册了的特效,都可以在avalon.effects对象中找到。 css3动画要求我们⾄少添加4个类名。这个是从angular那⾥学过来的。因此 如何你以前的项⽬是基于angular,它那些CSS动画类可以原封不动地搬过来 ⽤。 avalon.effect('animate', { enterClass: 'animate-enter', enterActiveClass: 'animate-enter-active', leaveClass: 'animate-leave', leaveActiveClass: 'animate-leave-active', }) 当然,这些类名会默认帮你添加,因为它内部是这样实现的。 ms-effect 92avalon.effect = function (name, definition) { avalon.effects[name] = definition || {} if (support.css) { if (!definition.enterClass) { definition.enterClass = name + '-enter' } if (!definition.enterActiveClass) { definition.enterActiveClass = definition.enterClass + ' -active' } if (!definition.leaveClass) { definition.leaveClass = name + '-leave' } if (!definition.leaveActiveClass) { definition.leaveActiveClass = definition.leaveClass + ' -active' } } if (!definition.action) { definition.action = 'enter' } } 因此你可以简化成这样: avalon.effect('animate', {}) avalon.effect('animate') 注册完,我们就需要在样式表中添加真正的CSS类。 ms-effect 93.animate-enter, .animate-leave{ width:100px; height:100px; background: #29b6f6; transition: width 2s; -moz-transition: width 2s; /* Firefox 4 */ -webkit-transition: width 2s; /* Safari 和 Chrome */ -o-transition: width 2s; /* Opera */ } .animate-enter-active, .animate-leave{ width:300px; } .animate-leave-active{ width:100px; } 我们还得定义⼀个vm,⾥⾯指明动画的动作(默认有三种⽅式, enter, leave, move) 及动画结束时的回调(这是可选的) var vm = avalon.define({ $id: 'effect', aaa: "test", action: 'enter', enterCb: function(){ avalon.log('动画完成') }, leaveCb: function(){ avalon.log('动画回到原点') } }) 然后⻚⾯上这样使⽤: ms-effect 94
{{@aaa}}
ms-effect的值为⼀个对象,其中is是必选。除了action, 还⽀持这么多种回 调: onEnterDone, onLeaveDone, onEnterAbort, onLeaveAbort, onBeforeEnter , onBeforeLeave 如果使⽤JS实现,则是这样的: TODO supply a title ms-effect 95 ms-effect 96
{{@aaa}}
⼀个CSS3位置效果 TODO supply a title
ms-widget+ms-for+ms-if+ms-effect的动画效果 ms-if
{{@aaa}}::{{el}}
ms-effect 100 ms-for与stagger的动画效果 这次为了与angular⼀致,stagger改为⼀个⼩数,它会让当前元素延迟 stagger秒执⾏。 ms-effect 103
{{item}}
⽬前,avalon的ms-effect可以与ms-visible,ms-if,ms-repeat连⽤。ms-effect 也可以单独或与其他指令使⽤,这时需要你指定action。
Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-08 01:52:53 ms-effect 104组件绑定 此绑定只能应⽤于wbr, xmp, template, 及ms-开头的⾃定义标签。它将在原 位置上转换成对应的组件的template的外观,加加上对应的数据与事件。 如果此组件没有注册(使⽤avalon.component进⾏定义),或其存在⼦组 件,⽽某个⼦组件没有注册,都会导致初始化失败。在对应位置上变成⼀个 注释节点。 有关组件的使⽤详看组件⼀章。 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-08 11:01:34 ms-widget 105⾃定义标签 以ms-开头的⾃定义标签, 我们需要⽤avalon.component⽅法定义它,然后在 ⾥⾯使⽤ms-widget指令 为它添加更多⾏为. avalon.component⽅法有两个参数,第⼀个标签名,必须以ms-开头;第⼆个是 配置对象. 配置对象⾥也有4个配置项 1. template,⾃定义标签的outerHTML,它必须是⽤⼀个普通的HTML元素节 点包起来,⾥⾯可以使⽤ ms-* 等指令 2. defaults,⽤来定义这个组件的VM有什么属性与⽅法 3. soleSlot,表示⾃定义标签的innerHTML为⼀个默认的插⼊点 (或可理解为 定义标签的innerHTML为当前组件某个属性的属性值) ,可选 4. getTemplate, ⽤来修改template, 依次传⼊vm与template, 返回新的模板. 可选 avalon.component('ms-pager', { template: '
< button type="button" ms-on-click="@onPlus">+++
', defaults: { num: 1, onPlus: function () { this.num++; } }, getTemplate: function(vm, template){ return template.replace('ms-on-click','ms-on-mousenter') } }); 注意,在avalon2中是严禁在绑定属性中混⼊插值表达式 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook ⾃定义标签 106该⽂件修订时间: 2016-07-08 00:55:28 ⾃定义标签 107组件 avalon拥有两⼤利器,强⼤的组件化功能以应对复杂墙问题,顶级的虚拟 DOM机制来解决性能墙问题。 组件可谓是指令的集合,但 1+1 > 2 ! 组件容器 组件容器是⼀个占位⽤的元素节点. 当avalon扫描到此位置上时将它替换成组 件. 在avalon2中有4类标签可以⽤作组件容器,分别是wbr, xmp, template, 及ms- 开头的⾃定义标签. 其兼容性如下 元素 类型 说明 wbr 所有浏览器, ⾃ 闭合标签 需要使⽤ms-widget来指定组件类型 xmp 所有浏览器, 闭 合标签 需要使⽤ms-widget来指定组件类型, ⾥⾯可以使⽤slot属性元素 template IE9+及W3C浏 览器,闭合标签 需要使⽤ms-widget来指定组件类型, ⾥⾯可以使⽤slot属性元素 ms-* IE9+及W3C浏 览器,闭合标签 可以省略ms-widget, ⾥⾯可以使⽤ slot属性元素 闭合标签,⽐如
⾃闭合标签,⽐如
根据上表, 如果要兼容IE6-8, 那么只能使⽤wbr, xmp来做组件容器 如果不打算⽀持IE, 那么使⽤template元素性能最好 如果追求语义化, 只⽀持IE9+及其他现代浏览器,则使⽤ms-*⾃定义标签. 组件 108xmp元素⾥⾯不能放xmp, template元素⾥⾯不能放template,这是html规 范,就像script元素⾥⾯不能放script, textarea元素⾥⾯不能放textarea. 但我们可以在这些元素⾥⾯直接放ms-*⾃定义标签. <ms-title slot="title">{{@title}}</ms-title> <xmp> 声明组件 如果我们想在⻚⾯上使⽤组件,需要⽤组件容器与ms-widget指令声明⼀下. <wbr ms-widget="{is:'ms-button'}" /> 这就是声明使⽤⼀个按钮组件. 当然还有其他三种⽅式 <xmp ms-widget="{is:'ms-button'}" /> ⾃定义标签都是闭合标签,不能写成下⾯这样 但是如果你的ms-button是放在xmp或template下⾯,则允许这样写. 组件 109 <ms-title slot="title" /> <div slot="content">这是弹出层的内容</div> <div slot="footer"> <ms-button :widget="@ok" /> <ms-button :widget="@ng" /> </div> <xmp> 组件命名 由于组件名在⾼级浏览器中,可以作⽤⾃定义标签的标签名.⽽HTML标签在 HTML5中有严格的规定, 只能出现 $,-,数字与英⽂单词, 并且只能以字⺟开头, 中间必须有'-'. 此外,为了⽅便avalon辨识这个标签名是否为⼀个数组,avalon强制规定以ms- 开头, 即 ms-button, ms-date-picker, ms-router-link 但是如果你不⽤⾃定义标签声明组件,使⽤ms-widget配置对象 来声明组件呢, 你就可以突破部分限制, 可以不以 ms- 开头 logger, date-picker, router-link <wbr ms-widget="{is:'texer'}" /> 配置对象 ms-widget 可以省略成 :widget ,它应该对应⼀个对象, 即配置对象. avalon2 的默认配置项⽐avalon1.5 少许多。所有组件通⽤的配置项 is, 字符串, 指定组件的类型。如果你使⽤了⾃定义标签,从标签名就得 知组件类型,则可以省略。 组件 110$id, 字符串, 指定组件vm的$id,这是可选项。如果该组件是位于SPA的 ⼦⻚⾥⾯,也请务必指定此配置项,能⼤⼤提⾼性能。 define, 函数, ⾃⼰决定如何创建vm,这是可选项。 onInit, onReady, onViewChange, onDispose四⼤⽣命周期钩⼦。 其他组件需要传⼊的属性与⽅法,也可以写配置对象中。 为了⽅便传数据, ms-widget也像ms-class那样能对应⼀个数组。 <wbr ms-widget="[@allConfig, {$id: 'xxx_'+$index}]"/> 此外, 如果你的组件是位于SPA的⼦⻚⾯中,或是由ms-html动态⽣成。 但组件对应的真实节点被移出DOM树时,该组件会被销毁。为了进⼀步提⾼ 性能,你可以在组件容器中定义⼀个cached属性,其值为true,它就能常驻 内存。 <wbr cached="true" ms-widget="[@allConfig, {$id: 'xxx_'+$index}]"/> ⽤了cached时,必须指定$id配置项。 插槽元素与插卡元素 为了⽅便传⼊很⻓的HTML格式的参数,web components规范发明了slot机 制。 avalon使⽤了⼀些⿊魔法也让旧式IE浏览器⽀持它。 通俗来说, 我们⽤组件容器为组件占位, 我们也⽤插槽容器为插卡元素占位. 我们看⼀下 ms-view 组件的定义与声明: 组件 111avalon.component('ms-view',{ template:"<div class="view"><slot name="content" /></div>", defaults: { content: "" } }) <div ms-controller='test'> <ms-view> <div slot="content">这是⼦视图的内容</div> </ms-view> </div> <slot name="content" /> 叫做插槽元素,⽤来占位的,实际上它在内部会转换 两个注释节点 <div class="view"> <!--slot:content--> <!--slot-end:--> </div> 组件容器中的带slot属性的元素, <div slot="content">这是⼦视图的内容 </div> ,就是插卡元素. 插卡元素最终会移动到组件对应的注释节点中去. <div class="view"> <!--slot:content--> <div slot="content">这是⼦视图的内容</div> <!--slot-end:--> </div> 我们可以对插卡元素使⽤除ms-if外的各种指令,如ms-for 组件 112<xmp :widget="{is:'ms-tabs',buttons: @buttons,tabs:@tabs}"> <div ms-for='(index,tab) in @tabs' ms-visible='index === @activeIndex ' slot='tabs' >{{tab}}</div> soleSlot机制 中⽂叫单插槽或匿名插槽. 这是插槽机制的⼀个特例. ⽐如我们做⼀个按钮组件: avalon.component('ms-button', { template: '', defaults: { buttonText: "button" } }) 那么外⾯要这么使⽤ xxx 事实上我们只想传⼊⼀个⽂本,不想传⼊b元素.这样定义太冗余了. 就像button标签,可以直接 于是就有单插槽机制. 它要求 组件 内部只有⼀个地⽅可以插东⻄, 并且将 组 件容器 的所有孩⼦或⽂本都作为⼀个插卡. 组件 113我们看⼀下新的定义与声明⽅式: avalon.component('ms-button', { template: '' , defaults: { buttonText: "button" }, soleSlot: 'buttonText' }) xxx avalon扫描后, ⽣成的组件是这个样⼦: 插槽机制可以解决我们传⼊⼤⽚内容的难题, 多个slot元素拥有同⼀个name 值。 组件 114组件定义 avalon定义组件时是使⽤avalon.component⽅法。 avalon.component⽅法有两个参数,第⼀个标签名,必须以ms-开头;第⼆个是 配置对象. 配置对象⾥也有4个配置项 template,⾃定义标签的outerHTML,它必须是⽤⼀个普通的HTML元素节 点包起来,⾥⾯可以使⽤ms-*等指令 defaults,⽤来定义这个组件的VM有什么属性与⽅法 soleSlot,表示组件只有⼀个插槽,会将组件容器的所有孩⼦都移到这⾥来 , 可选。 getTemplate, ⽤来修改template, 依次传⼊vm与template, 返回新的模 板, 可选。 组件 115avalon.component('ms-pager', { template: '
< button type="button" ms-on-click="@onPlus">+++
', defaults: { num: 1, onPlus: function () { this.num++; } }, getTemplate: function(vm, template){ return template.replace('ms-on-click','ms-on-mousenter') } }); 渲染真相 var widgetVTree = widgetName(widgetOptions, slots, getTemplate(temp late)) /* widgetName: ms-widget中的is配置项或⾃定义标签的标签名 widgetOptions: ms-widget配置项 slots: 所有插卡元素组成的对象 getTemplate: 组件定义中getTemplate配置项 template: 组件定义中template配置项 widgetVTree: 组件的虚拟DOM, */ ⽣命周期 avalon2组件拥有完善的⽣命周期钩⼦,⽅便⼤家做各种操作。 组件 116avalon2 web component react 初始 化 onInit createdCallback getDefaultProps 插⼊ DOM 树 onReady attachedCallback componentDidMount 视图 变化 onViewChange attributeChangedCallback componentDidUpdate 移出 DOM 树 onDispose detachedCallback componentWillUnmount onInit,这是组件的vm创建完毕就⽴即调⽤时,这时它对应的元素节点或虚 拟DOM都不存在。只有当这个组件⾥⾯不存在⼦组件或⼦组件的构造器都加 载回来,那么它才开始创建其虚拟DOM。否则原位置上被⼀个注释节点占 着。 onReady,当其虚拟DOM构建完毕,它就⽣成其真实DOM,并⽤它插⼊到 DOM树,替换掉那个注释节点。相当于其他框架的attachedCallback, inserted, componentDidMount. onViewChange,当这个组件或其⼦孙节点的某些属性值或⽂本内容发⽣变 化,就会触发它。它是⽐Web Component的attributeChangedCallback更加 给⼒。 onDispose,当这个组件的元素被移出DOM树,就会执⾏此回调,它会移除 相应的事件,数据与vmodel。 ⼯作原理 avalon会先将组件容器转换为⼀个渲染函数,传⼊组件VM,成⼀个虚拟 DOM(shellRoot) 再将组件定义中的template转换为第⼆个渲染函数,传⼊组件VM,成⼀个虚拟 DOM(component) 组件 117然后将shellRoot的最外层元素的所有属性合并到component的最外层的元素 上. 再将shellRoot中的插卡元素, 插⼊到component中的插槽元素的位置上. 将component变成真实DOM,替换组件容器. 具体例⼦ 请移步到Github 官⽅组件集 Promise mmPromise npm install avalon-promise ajax组件 mmRequest npm install mmPequest redux事件派发组件 mmDux npm install mmDux 路由组件 组件 118mmRouter 动画组件 虽然avalon2已经拥有ms-effect指令,但那是基于CSS3的,在IE6-8下是需要JS 库来⽀持 mmAnimate npm install mmAnimate 弹窗组件 ms-modal npm install ms-modal 分⻚组件 ms-pager npm install ms-pager 切换卡组件 ms-tabs npm install ms-tabs Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-30 01:55:39 组件 119过滤器 格式化过滤器 ⽤于处理数字或字符串,多⽤ 于{{}} 或ms-attr或ms-class 注意: avalon的过滤器与ng的过滤器在传参上有点不⼀样,需要⽤()括起 来 uppercase 将字符串全部⼤写 vm.aaa = "aaa"
{{@aaa | uppercase}}
lowercase 将字符串全部⼩写 vm.aaa = "AAA"
{{@aaa | lowercase}}
truncate 对⻓字符串进⾏截短,有两个可选参数 number,最后返回的字符串的⻓度,已经将truncation的⻓度包含在内,默 认为30。 truncation,告知⽤户它已经被截短的⼀个结尾标识,默认为"..." 过滤器 120vm.aaa = "121323234324324"
{{@aaa | truncate(10,'...')}}
camelize 驼峰化处理, 如"aaa-bbb"变成"aaaBBB" escape 对类似于HTML格式的字符串进⾏转义,如将<、 >转换为<、 > sanitize 对⽤户输⼊的字符串进⾏反XSS处理,去掉onclick, javascript:alert ,

输⼊数字:

不处理:{{@aaa}}

不传参:{{@aaa|number}}

不保留⼩数:{{@aaa|number(0)}}

负数:{{-@aaa|number(4)}}

currency ⽤于格式化货币,类似于number过滤器(即插⼊千分号),但前⾯加了⼀个 货币符号,默认使⽤⼈⺠币符号 \uFFE5 symbol, 货币符号,默认是 \uFFE5 fractionSize,⼩数点后保留多少数,默 认是2 过滤器 122date 对⽇期进⾏格式化,date(formats), ⽬标可能是符合⼀定格式的字符串,数 值,或Date对象。 TODO supply a title

⽣成于{{ @d1 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d2 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d3 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d4 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d5 | date("yyyy MM dd:HH:mm:ss")}}

过滤器 123

⽣成于{{ @d6 | date("yyyy MM dd")}}

⽣成于{{ @d7 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d8 | date("yyyy MM dd:HH:mm:ss")}}

⽣成于{{ @d9 | date("yyyy MM dd:HH:mm:ss")}} //这是ISO860 1的⽇期格式

⽣成于{{ @d10| date("yyyy MM dd:HH:mm:ss")}} //这是ASP.NE T输出的JSON数据的⽇期格式

标记 说明 yyyy 将当前的年份以4位数输出,如果那⼀年为300,则补 ⾜为0300 yy 将当前的年份截取最后两位数输出,如2014变成14, 1999变成99, 2001变成01 y 将当前的年份原样输出,如2014变成2014, 399变成 399, 1变成1 MMMM 在中⽂中,MMMM与MMM是没有区别,都是"1 ⽉","2⽉"……英语则为该⽉份的单词全拼 MMM 在中⽂中,MMMM与MMM是没有区别,都是"1 ⽉","2⽉"……英语则为该⽉份的单词缩写(前三个字 ⺟) MM 将⽉份以01-12的形式输出(即不到两位数,前⾯补0) M 将⽉份以1-12的形式输出 dd 以⽇期以01-31的形式输出(即不到两位数,前⾯补0) d 以⽇期以1-31的形式输出 EEEE 将当前天的星期⼏以“星期⼀”,“星期⼆”,“星期⽇”的 形式输出,英语则Sunday-Saturday EEE 将当前天的星期⼏以“周⼀”,“周⼆”,“周⽇”的形式输 出,英语则Sun-Sat 过滤器 124HH 将当前⼩时数以00-23的形式输出 H 将当前⼩时数以0-23的形式输出 hh 将当前⼩时数以01-12的形式输出 h 将当前⼩时数以0-12的形式输出 mm 将当前分钟数以00-59的形式输出 m 将当前分钟数以0-59的形式输出 ss 将当前秒数以00-59的形式输出 s 将当前秒数以0-59的形式输出 a 将当前时间是以“上午”,“下午”的形式输出 Z 将当前时间的时区以-1200-+1200的形式输出 fullDate 相当于y年M⽉d⽇EEEE 2014年12⽉31⽇星期三 longDate 相当于y年M⽉d⽇EEEE 2014年12⽉31⽇ medium 相当于yyyy-M-d H:mm:ss 2014-12-31 19:02:44 mediumDate 相当于yyyy-M-d 2014-12-31 mediumTime 相当于H:mm:ss 19:02:44 short 相当于yy-M-d ah:mm 14-12-31 下午7:02 shortDate 相当于yy-M-d 14-12-31 shortTime 相当于ah:mm 下午7:02 循环过滤器 ⽤于ms-for指令中 limitBy 过滤器 125只能⽤于ms-for循环,对数组与对象都有效, 限制输出到⻚⾯的个数, 有两个参 数 1. limit: 最⼤个数,必须是数字或字符, 当个数超出数组⻓或键值对总数时, 等 于后⾯ 2. begin: 开始循环的个数, 可选,默认0
  • {{el}}
  • {{el}}
orderBy 只能⽤于ms-for循环,对数组与对象都有效, ⽤于排序, 有两个参数 1. key: 要排序的属性名 2. dir: -1或1, 顺序或倒序,可选,默认1 过滤器 126
{{elem}}
filterBy 只能⽤于ms-for循环,对数组与对象都有效, ⽤于获取它们的某⼀⼦集, 有⾄少 ⼀个参数 search,如果为函数时, 通过返回true决定成为⼦集的⼀部分; 如果是字符串 或数字, 将转换成正则, 如果数组元素或对象键值匹配它,则成为⼦集的⼀部 分,但如果是空字符串则返回原对象 ;其他情况也返回原对象。 其他参数, 只 有当search为函数时有效, 这时其参数依次是组元素或对象键值, 索引值, 多 余的参数 此过滤多⽤于⾃动完成的模糊匹配!

  • {{el}}
  • {{el}}
` 过滤器 128selectBy 只能⽤于ms-for循环,只对对象有效, ⽤于抽取⽬标对象的⼏个值,构成新数组 返回. 1. array,要抽取的属性名 2. defaults,如果⽬标对象不存在这个属性,那么从这个默认对象中得到默 认值,否则为空字符串, 可选 这个多⽤于表格, 每⼀列的对象可能存在属性 顺序不⼀致或缺少的情况 过滤器 129
  • {{el}}
{{td}}
事件过滤器 事件过滤器只要是对⼀些常⽤操作进⾏简化处理 对按键事件(keyup,keydown,keypress)到底按下了哪些功能键 或⽅向键进⾏ 友好的处理.许多⼈都记不清回⻋退格的keyCode是多少. 对阻⽌默认⾏为与 防⽌冒泡进⾏封装 esc 过滤器 130当⽤户按下esc键时,执⾏你的回调 tab 当⽤户按下tab键时,执⾏你的回调 enter 当⽤户按下enter键时,执⾏你的回调 space 当⽤户按下space键时,执⾏你的回调 del 当⽤户按下del键时,执⾏你的回调 up 当⽤户按下up键时,执⾏你的回调 down 当⽤户按下down键时,执⾏你的回调 left 当⽤户按下left键时,执⾏你的回调 right 当⽤户按下right键时,执⾏你的回调 过滤器 131prevent 阻⽌默为⾏为,多⽤于form的submit事件防⽌⻚⾯跳转,相当于调⽤了 event.preventDefault 阻⽌跳转 stop 阻⽌事件冒泡,相当于调⽤了event.stopPropagation ⻚⾯的过滤器只能⽤于事件绑定 同步频率过滤器 这两个过滤器只⽤于ms-duplex change 在⽂本域或⽂本区使⽤ms-duplex时,默认是每输⼊⼀个字符就同步⼀次. 当我 们想在失去焦点时才进⾏同步, 那么可以使⽤此过滤器 {{@aaa}} debounce 当我们实现搜索框的⾃动完成时, 每输⼊⼀个字符可能就会向后台请求⼀次 (请求关键字列表), 这样太频繁,后端撑不住,但使⽤change过滤器,则⼜太慢了. 改为每隔⼏⼗毫秒请求⼀次就最好. 基于此常⽤需要开发出此过滤器. 拥有⼀ 个参数. 1. debounceTime: 数字, 不写默认是300,不能少于4,否则做⽆效处理 过滤器 132 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-12 15:46:41 过滤器 133类型转换器 由于我们从表单元素拿到的所有东⻄都是字符串或字符串数组, 因此 从 avalon0.* 起就提供了⼏个ms-duplex的辅助指令来实现数据类型转换功 能 格式为 ms-duplex-xxxx 默认提供了4个数据转换器 ms-duplex-string ms-duplex-number ms-duplex-boolean ms-duplex-checked 具体⽤法详⻅双⼯绑定 {{@aaa}} 我们也可以⾃定义类型转换器, 直接在avalon.parser上添加 类型转换器 134parsers: { number: function (a) { return a === '' ? '' : /\d\.$/.test(a) ? a : parseFloat(a) || 0 }, string: function (a) { return a === null || a === void 0 ? '' : a + '' }, boolean: function (a) { if(a === '') return a return a === 'true'|| a == '1' } }, 上⾯number, string, boolean就是ms-duplex-xxx的实际转换⽅法, a为元素的 value值. ms-duplex-checked⽐较特殊它是使⽤checked属性,因此不在其列. 上⾯number, string, boolean就是ms-duplex-xxx的实际转换⽅法, a为元素的 value值. ms-duplex-checked⽐较特殊它是使⽤checked属性,因此不在其列. 我们看⼀下转换器的⽤法。

{{@aaa}}

类型转换器 135如果不使⽤ms-duplex-number转换器,最开始时,第⼀个,第⼆个checkbox 是能正确选中,但当我们点击第⼆个时,发现下⾯的⽂本没有变化。 因此我 们是尝试从[1,2]数组中移除"2"这个字符串,当然移除不了,没有效果。 当我们改成这样 点击第⼆个checkbox时,它会转换出input.value的“2”,然后再⽤ avalon.parsers.number转换成数字,就能成功移除,于是⽂本就会变化。 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-11 20:38:09 类型转换器 136表单验证 avalon内置了强⼤的表单验证功能,它需要结合ms-duplex, ms-validate, ms- rules这个三个指令⼀起使⽤。 ms-duplex负责监控每个表单元素的输⼊。 ms-rules负责对表单元素的值进⾏各种检测,包括⾮空验证,⻓度验 测,格式匹配等等。 ms-validate负责控制验证的时机,及针对每个表单元素的验证结果触发 各种回调。 验证规则定义在avalon.validators对象中, 为⼀个个带有message与get属性的 对象. 具体⽤法详⻅验证规则绑定 表单验证 137avalon.shadowCopy(avalon.validators, { pattern: { message: '必须匹配{{pattern}}这样的格式', get: function (value, field, next) { var elem = field.element var data = field.data if (!isRegExp(data.pattern)) { var h5pattern = elem.getAttribute("pattern") data.pattern = new RegExp('^(?:' + h5pattern + ')$' ) } next(data.pattern.test(value)) return value } }, digits: { message: '必须整数', get: function (value, field, next) {//整数 next(/^\-?\d+$/.test(value)) return value } }, number: { message: '必须数字', get: function (value, field, next) {//数值 next(isFinite(value)) return value } } }) Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-08 03:14:32 表单验证 138配置 avalon2遵循coc原则,配置项⽐较少。只有两个配置项。 双花括号也默认是python⼀些著名模板的界定符,为了防⽌冲突,我们有更 换界定符的需求。 这时我们可以这样做 avalon.config({ interpolate: ['{%','%}'] }) //或 avalon.config({ interpolate: ['{?','?}'] }) //或 avalon.config({ interpolate: ['{&','&}'] }) 注意,左右界定符的⻓度应该为2,并且不能出现 < , > ,因为出现源码括号在 旧式IE下会变成注释节点 我们再看下⼀个有⽤的配置项,debug。avalon默 认是在控制台下打印没有调试消息的, 上线时我们不愿⽤户看到它们,可以 这样关掉它们。 avalon.config({ debug: false }) Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-11 20:39:55 配置 139移动端⽀持 avalon在这⾥提供了⼏种⼿势模块, 来满⾜你的移动开发. PC端与移动端的事件是完全不⼀样,移动端的⼤多数事件都是基于 ontouchxxx事件合成出来. 这些JS, 我们在使⽤时,可以直接这样 var avalon = require('../avalon') var tap = require('../tap') 使⽤时
点我
当你使⽤tap模块,请把tap与recognizer.js模块放在同⼀⽂件夹下. drag, pinch, press, rotate, swipe, tap都依赖于recongizer模块. 具体教程可以看这⾥ drag模块:在指定的dom区域内,⼀个⼿指放下并移动事件,即触屏中的拖 动事件。这个事件在屏触开发中⽐较常⽤,如:左拖动、右拖动等. 如⼿要上 使⽤QQ时向右滑动出现功能菜单的效果。具体事件有: 1. dragstart:拖动开始 2. dragmove:拖动过程 3. dragend:拖动结束 pinch模块:在指定的dom区域内,两个⼿指相对(越来越近)移动或相向 (越来越远)移动时事件。 具体事件有: 1. pinchstart:多点触控开始 2. pinch:多点触控过程 3. pinchend:多点触控结束 4. pinchin:多点触控时两⼿指距离越来越近 移动端⽀持 1405. pinchout:多点触控时两⼿指距离越来越远 press模块:在指定的dom区域内触屏版本的点击事件(longtap),这个事件相 当于PC端的click事件, 该不能包含任何的移动,最⼩按压时间为500毫秒, 常⽤于我们在⼿机上⽤的“复制、粘贴”等功能。 具体事件有: 1. longtap:⻓按 2. doubletap: 双击 rotate模块:在指定的dom区域内,当单个⼿指围绕某个点转动时触发事件. 具体事件有: 1. rotatestart:旋转开始 2. rotatemove:旋转过程 3. rotateend:旋转结束 swipe模块:在指定的dom区域内,⼀个⼿指快速的在触屏上滑动。即我们 平时⽤到最多的滑动事件。 具体事件有: 1. swipeleft:向左滑动 2. swiperight:向右滑动 3. swipeup:向上滑动 4. swipedown:向下滑动 5. swipe: 滑动(可以通过事件对象的direction属性知道当前滑动⽅向) tap模块:在指定的dom区域内,⼀个⼿指轻拍或点击时触发该事件(类似PC 端的click)。 该事件最⼤点击时间为250毫秒,如果超过250毫秒则按longtap 事件进⾏处理。 具体事件有: 1. tap: 轻拍 另外针对众多⼿机浏览器的奇怪设定,我们需要做⼀些hack 移动端⽀持 141 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-20 11:15:34 移动端⽀持 142移动端⽀持 143常⻅问题 如何隐藏⾸屏加载⻚⾯时出现的花括号 答 :在⻚⾯上添加⼀个样式 .ms-controller{ visibility: hidden } 使⽤在ms-controller, ms-important的元素上加上这个ms-controller类名 IE6-8下为vm的数组重新赋给⼀个新数组失败? 具体案例 vm.arr2 = vm.arr1 //报错 记住,任何时候,不能将vm中的数组或⼦对象取出来,再⽤它们赋给vm的某个数 组或⼦对象, 因为放在vm中的数组与⼦对象已经变成VM了,⽽VM重写VM不 被允许的. 并且你要保证原数据不被污染,需要使⽤深拷⻉. vm.arr2 = avalon.mix(true, [], arr1) vm.obj2 = avalon.mix(true, {}, obj1) 你也可以这样,将原数据转换为纯数据就⾏了 vm.arr2 = vm.arr1.$model //正常 常⻅问题 144为什么我的指令没有效果?

例⼦!

答 :因为avalon只会对 ms-* 属性敏感, 另外, 花括号⾥的ddd要加上 @ ,即

例⼦!

如何在⻚⾯扫描后执⾏⼀个回调 答 : avalon2⽀持onReady⽅法 var vm = avalon.define({ $id: 'test', ddd: false }) vm.$watch('onReady', function(){ //当test这个区域第⼀次扫描后会被执⾏ }) 详⻅API⽂档⻚ 对表单元素的值输⼊进⾏限制 答 : avalon提供了4个转换器,那是将value值上传到vm时⽤,也提供了许多格 式式过滤器, 但在ms-duplex格式化很容易死循环,因此建议在另加input事件做 处理. ⽐如说我们限制只能输⼊数字 常⻅问题 145 {{@aaa}} 如果⼿动执⾏验证 答 : ms-validate提供了各种全⾃动的验证.但可能⼤家需要⼿动执⾏验证表 单 在ms-validate的配置对象上添加⼀个onManual,⻚⾯被扫描后,你就可能拿 这个⽅法来⾃⼰执⾏验证 Drag-Drop

{{@a aa}}

常⻅问题 147 ⻚⾯⽤了avalon后, 元素间没有距离了 答: 因为avalon在⻚⾯加载好后,会清掉所有空⽩⽂本,减少⻚⾯的节点数,从⽽ 减少以后diff的节点个数. 详⻅这⾥. 组件的注意事项 答 : 最好指定全局不重复的$id,特别在ms-for循环中,必须指定$id 常⻅问题 148
为什么我的⽇期不能同步 常⻅问题 149var vm = avalon.define({ $id:'aaa', date: new Date }) setTimeout(function(){ vm.date = new Date }, 1000) 答 : 因为avalon只会对number, string, boolean, 纯对象, 纯数组这⼏个类型 同步, 其他类型需要转换. 将上⾯的 new Date 改成 new Date - 0 即可 Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-19 01:34:17 常⻅问题 150与jQuery共存 jQuery是世界上最流⾏的DOM库,它拥有各式各样的插件,在⽇常开发中我们 可能还是离不开它.因此与它⼀起使⽤是常态, 下⾯是⼀些注意 domReady后如何扫描 $(function(){ var vm = avalon.define({/* */}) //如果你将vm定义在jQuery的ready⽅法内部,那么avalon的扫描就会失效,需 要⼿动扫描 avalon.scan(document.body) //现在只要传⼊扫描范围的根节点就⾏ }) 如何AJAX提交数据 提交整个VM jQuery.ajax({ method: "POST", url: 'url-adress', //这⾥是取vm的数据模型 ,通过JSON.stringify会去掉其所有⽅法, 变成JSON 字符串 //再⽤JSON.parse变回纯JS对象 data: JSON.parse(JSON.stringify(vm.$model)) }) 提交VM中的某个 对象 属性 与jQuery混⽤ 151data: JSON.parse(JSON.stringify(vm.data.$model)) `` 提交VM中的某个`数组`属性 ```javascript data: JSON.parse(JSON.stringify(vm.data.$model)) 如何让后台回来的数据更新VM 后台的数据更新VM,只能是更新VM的某些已经定义属性. 如果后台数据很⼤, 那么我们可以定义⼀个空对象(假如后台数据是对象类型)或⼀个空数组(假如 后台数据是数组类型)来占位 var vm = avalon.define({ $id: 'aaa', array: [] }) jQuery.ajax({ method: "POST", url: 'url-adress', data: {/**/}, success: function(data){ vm.array = data.array } }) 如何同步表单的数据 假如我的某个表单是⽤于jQuery的⽇历插件,那么它数据如何同步到vm 与jQuery混⽤ 152$(datepick_input_css_selector).input(function(){ vm.aaa = this.value }) 如何同步复选框 在avalon中,checkbox要对应⼀个数组 ⾸选是取得所有同名 的checkbox,并要求它们在选中状态,然后⽤map⽅法收集它们的value值 $('checkbox').change(function(){ var array = $('checkbox[name="'+this.name+'"]:checked').map(func tion(){ return $(this).val(); }) vm.checkboxProps = array }) 如何同步下拉框 $('select').change(function(){ vm.selectProps = $(this).val() }) Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-20 11:11:41 与jQuery混⽤ 153API 静态成员 scan ⽤于描述HTML,将包括ms-controller/ms-imporant的元素的outerHTML取出 来, 变成对应的vm的render⽅法, 最终将⾥⾯的ms-*或双花括号变成vm中的 属性与⽅法 注意: 如果你是将vm定义放在jQuery.ready或avalon.ready中必须⼿动 调⽤这个⽅法. 注意: avalon2不会像avalon1那样将ms-*属性去掉了 注意: avalon不能扫描iframe的内容 有两个参数 1. 元素节点 avalon.ready(function(){ avalon.define({ $id: 'test', aaa: 111 }) avalon.scan(document.body) vm.$watch('onReady', function(){ //⻚⾯上每个ms-controller, ms-important元素 //在其区域内的所有ms-*指令被扫描后会执⾏ }) }) onReady回调,在2.1.0新加⼊,只会调⽤⼀次! API 154
{{@fff}}
define 创建⼀个vm对象,必须指定$id,详⻅这⾥ API 157avalon.define({ $id: 'aaa', bbb: 1 }) noop 空函数 rword 切割字符串为⼀个个⼩块,以空格或逗号分开它们,结合replace实现字符串 的forEach "aaa,bbb,ccc".replace(avalon.rword, function(a){ console.log(a)//依次打出 aaa, bbb, ccc return a }) log 类似于console.log,但更安全,因为IE6没有console.log,⽽IE7下必须打开调试 界⾯才有console.log 可以传⼊多个参数 avalon.log('aaa','bbb') warn avalon.warn('aaa','bbb') API 158类似于console.warn, 不存在时内部调⽤avalon.log error 抛出⼀个异常对象 1. 字符串,错误消息 2. 可选, Error对象的构造器(如果是纯字符串,在某些控制台下会乱码,因此必 须包成⼀个对象) avalon.error('aaa') oneObject 将⼀个以空格或逗号隔开的字符串或数组,转换成⼀个键值都为1的对象 1. 以空格或逗号隔开的字符串或数组, "aaa,bbb,ccc",['aaa','bbb','ccc'] 2. ⽣成的对象的键值都是什么值,默认1 avalon.oneObject("aaa,bbb,ccc")//{aaa:1,bbb:1,ccc:1} isWindow 判定是否为⼀个window对象 avalon.isWindow('ddd')//false isFunction 判定是否为⼀个函数 avalon.isFunction(window.alert)//true API 159isObject 是否为⼀个对象, 返回布尔 avalon.isObject({a:1,b:2})//true avalon.isObject(window.alert) //true avalon.isObject('aaa') //false type 取得⽬标的类型 avalon.type('str') //'string' avalon.type(123) //'number' avalon.type(/\w+/) //'regexp' avalon.type(avalon.noop) //'function' isPlainObject 判定是否为⼀个纯净的JS对象, 不能为window, 任何类(包括⾃定义类)的实例, 元素节点,⽂本节点 ⽤于内部的深克隆, VM的赋值, each⽅法 avalon.isPlainObject({}) //true avalon.isPlainObject(new Object) //true avalon.isPlainObject(Object.create(null)) //true var A = function(){} avalon.isPlainObject(new A) //false each ⽤于遍历对象或类数组,数组 API 160avalon.each(arr, function(index, el){ }) mix ⽤于合并多个对象或深克隆,类似于jQuery.extend 注意,不要加VM批量赋值时⽤它 //合并多个对象,返回第⼀个参数 target = avalon.mix(target, obj1, obj2, obj3) //深拷⻉模式, 要求第⼀个参数为true, 返回第⼆个参数 target = avalon.mix(true, target, obj1, obj2) vmodels 放置所有⽤户定义的vm及组件指令产⽣的组件vm avalon.define({$id:'aaa'}) console.log(avalon.vmodels) // {aaa: vm} filters 放置所有过滤器,也可以在上⾯添加你的⾃定义过滤器 avalon.filters.haha = function(str){ return str + 'haha' } components 放置所有⽤avalon.component⽅法添加的组件配置对象 API 161validators 放置所有验证规则,详⻅这⾥ parsers 放置所有数据格式转换器 slice ⽤于转换类数组对象为纯数组对象 1. ⽬示对象 2. 开始索引, 默认为0 3. 结束索引, 默认为总⻓ avalon.slice(document.body.childNodes) directive 定义⼀个指令, 请翻看源码,看css, attr, html是怎么玩的 1. 指令名 2. 配置对象 API 162avalon.directive('html', { parse: function (copy, src, binding) { /* copy: 每次VM的属性时,avalon就会调⽤vm.$render⽅法重新⽣成⼀个虚 拟DOM树 ,这个copy就是新虚拟DOM树的⼀个⼦孙节点 src: 第⼀次调⽤vm.$render⽅法⽣成的虚拟DOM树的某个节点,它将永驻 于内存中, 除⾮其对应的真实节点被移除.以后不断⽤src与新⽣成的copy进⾏⽐较, 然后应⽤ update⽅法,最后⽤copy的属性更新src与真实DOM. binding 配置对象,包括name,expr,type,param等配置项 return ⽤于⽣成vtree的字符串 */ }, diff: function (copy, src, name) { /* copy 刚刚⽣成的虚拟DOM树的某个⼦孙节点 src 最初的虚拟DOM树的节点 name 要⽐较的指令名 */ }, update: function (node, vnode, parent) { /* node 当前的真实节点 vnode 此真实节点在虚拟树的相应位置对应的虚拟节点 parent node.parentNode */ } }) effect ⽤于定义⼀个动画效果,详⻅这⾥ API 163component ⽤于定义⼀个组件,详⻅这⾥ range ⽤于⽣成整数数组 1. start 开始值, 2. end 结束值, 可以为负数 3. step 每隔多少个整数 avalon.range(10) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] avalon.range(1, 11) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] avalon.range(0, 30, 5) => [0, 5, 10, 15, 20, 25] avalon.range(0, -10, -1) => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] avalon.range(0) hyphen 转换为连字符线⻛格 avalon.hyphen('aaaAaa') //aaa-aaa camelize 转换为驼峰⻛格 avalon.hyphen('aaa-Bbb') //aaaBBB API 164bind 添加事件 1. 元素节点,window, document 2. 事件名 3. 回调 4. 是否捕获,可选 avalon.bind(window, 'load',loadFn) unbind 移除事件 参数与bind⽅法相同 parseHTML 转换⼀段HTML字符串为⼀个⽂档对象 avalon.parseHTML('222333') innerHTML 类似于 element.innerHTML = newHTML ,但兼容性更好 1. node 元素节点 2. 要替换的HTML字符串 var elem = document.getElementById('aaa') avalon.innerHTML(elem, '222333') clearHTML ⽤于清空元素的内部 API 165avalon.clearHTML(elem) contains 判定A节点是否包含B节点 1. A 元素节点 2. B 元素节点 avalon.contains(document.body, document.querySelector('a')) Array Array.merge 合并两个数组 avalon.Array.merge(arr1,arr2) Array.ensure 只有当前数组不存在此元素时只添加它 avalon.Array.ensure([1,2,3],3)//[1,2,3] avalon.Array.ensure([1,2,3],8)//[1,2,3,8] Array.removeAt 移除数组中指定位置的元素,返回布尔表示成功与否 avalon.Array.removeAt([1,2,3],1)//[1,3] API 166Array.remove 移除数组中第⼀个匹配传参的那个元素,返回布尔表示成功与否 avalon.Array.remove(['a','b','c'],'a')//['b','c'] 被修复了的ecma262⽅法 1. String.prototype.trim 2. Function.prototype.bind 3. Array.isArray avalon内部使⽤它判定是否数组 4. Object.keys 5. Array.prototype.slice IE6-8下有BUG,这⾥做了修复 6. Array.prototype.indexOf 7. Array.prototype.lastIndexOf 8. Array.prototype.forEach 9. Array.prototype.map 10. Array.prototype.filter 11. Array.prototype.some 12. Array.prototype.every 实例成员 avalon 1. 可以传⼊元素节点,⽂档对象,window对象构成⼀个avalon实例 var a = avalon(document.body) console.log(a[0]) //document.body console.log(a.element) // document.body API 167与jQuery对象不同的是,它只能传⼊⼀个元素或对象, ⽽jQuery是可以传 ⼊CSS选符串获得⼀⼤堆元素节点,组成⼀个类数组对象 avalon作为⼀ 个MVVM框架, ⽬的是实现最⼩化刷新, 通常没有操作⼀⼤堆节点的需求 avalon的实例⽅法主要供框架内部使⽤,除了⾃⼰写组件,所有操作的 DOM的需求请使⽤ms- 如果要使⽤第三⽅的jQuery插件,请务必将它们 封装成*avalon的组件 css ⽤于获取或修改样式,⾃动修正⼚商前缀及加px,与jQuery的css⽅法⼀样智能 avalon(elem).css('float','left') width API 168取得⽬标的宽,不带单位,如果⽬标为window,则取得窗⼝的宽,为document取 得⻚⾯的宽 avalon(elem).width() height 取得⽬标的⾼,不带单位,如果⽬标为window,则取得窗⼝的⾼,为document取 得⻚⾯的⾼ innerWidth 类似于jQuery的innerWidth innerHeight 类似于jQuery的innerHeight outerWidth 类似于jQuery的outerWidth outerHeight 类似于jQuery的outerHeight offset 取得元素的位置, 如 {top:111, left: 222} attr ⽤于获取或修改属性 API 169avalon(elem).attr('title','aaa') 注意,这个⽅法内部只使⽤setAttribute及getAttribute⽅法,⾮常弱 建议使 ⽤ms-attr指令实现相同的功能 addClass 添加多个类名, 以空格隔开 avalon(elem).addClass('red aaa bbb') removeClass 移除多个类名, 以空格隔开 avalon(elem).removeClass('red aaa bbb') hasClass 判定⽬标元素是否包含某个类名 toggleClass 切换多个类名 1. 类名,以空格隔开 2. 可选, 为布尔时强制添加或删除这些类名 avalon(elem).toggleClass('aaa bbb ccc') bind API 170类似于avalon.bind avalon(elem).bind('click', clickFn) unbind 类似于avalon.unbind Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 该⽂件修订时间: 2016-07-13 15:24:42 API 171更新⽇志 2.1.8 component/initjs中的protected变量更名为immunity,⽅便在严格模式下运⾏ 为伪事件对象过滤掉原⽣事件对象中的常量属性 修复class,hover,active指令互相⼲扰的BUG 修复事件绑定中表达式太复杂,不会补上($event)的BUG 当组件被移出DOM树并且没有被cached时,其虚拟DOM应该清空上⾯的事件 2.1.7 修正注释节点包括HTML结构(⾥⾯有引号),节点对⻬算法崩溃的BUG 修正tap事件误触发BUG 升级ms-widget的slot机制,让它们的值也放到组件VM中 添加:xxx短指令的⽀持 2.1.6 全新的lexer与插值表达式抽取⽅法 添加unescapeHTML与escapeHTML⽅法 修正xmp元素的内容⽣成BUG 修正input.value = newValue的同步BUG 修正双击事件BUG 修正ms-widget遇上ms-if找到原先占位DOM的BUG 更新⽇志 1722.1.5 添加htmlfy模块 ⽤于解决IE6-7对colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr元素 ⾃闭合,html parser解析出错的问题 重构ms-controller, ms-important指令 虚拟DOM移除template属性 修正ms-for的排序问题 fix 在chrome与firefox下删掉select中的空⽩节点,会影响到selectedIndex BUG 2.1.4 修复IE光标问题 修复输⼊法问题 修复双层注释节点ms-for循环问题(markRepeatRange BUG) ms-html中script, style标签不⽣效的问题 2.1.3 修正isSkip⽅法,阻⽌regexp, window, date被转换成⼦VM checkbox改⽤click事件来同步VM #1532 ms-duplex-string在radio 的更新失效问题 2.1.2 更新⽇志 173ms-for+expr在option元素不显示的问题(实质是节点对⻬问题) 模板中的©×没有被htmlDecode的问题 绑定在组件模板中最外层元素上的事件不⽣效 ie7,8下 ms-duplex 因为onproppertychange环调⽤,导致辞爆栈的问题 修正节点对⻬算法中 对空⽩节点与script等容器处理的处理 2.1.1 简化VElement转换DOM的逻辑 将改 order的连接符为 ‘,’,这样就可以重⽤更简单的avalon.rword 修正e.which BUG 修正 ms-duplex-checked在低版本浏览器不断闪烁的问题 2.1.0 重构lexer⽅法 添加新的对⻬节点算法 修复IE6-8下复制闭包中的对象返回相同对象,导致ms-for出BUG的问题 所有vm都⽀持onReady,在它第⼀次刷新作⽤区载时触发 重构ms-for, ms-html,ms-if,ms-text,ms-html,ms-on指令 参考react 的classNames插件,重构ms-class/active/hover, 上线全新的parseHTML,内部基于avalon.lexer,能完美⽣成script, xml,svg 元素 重构isInCache, saveInCache Copyright © 司徒正美 2013-2016 all right reserved,powered by Gitbook 更新⽇志 174该⽂件修订时间: 2016-07-27 16:38:55 更新⽇志 175
还剩174页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

414220089

贡献于2016-09-07

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf