avalonjs 入门教程.doc_第1页
avalonjs 入门教程.doc_第2页
avalonjs 入门教程.doc_第3页
avalonjs 入门教程.doc_第4页
avalonjs 入门教程.doc_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1. 关于AvalonJs2. 开始的例子3. 扫描4. 视图模型5. 数据模型6. 绑定属性与动态模板7. 作用域绑定(ms-controller, ms-important)8. 模板绑定(ms-include)9. 数据填充(ms-text, ms-html)10. 类名切换(ms-class, ms-hover, ms-active)11. 事件绑定(ms-on,)12. 显示绑定(ms-visible)13. 插入绑定(ms-if)14. 双工绑定(ms-duplex,原来的ms-model)15. 样式绑定(ms-css)16. 数据绑定(ms-data)17. 布尔属性绑定(ms-checked, ms-selected, ms-readonly, ms-disabled, ms-enabled)18. 字符串属性绑定(ms-title, ms-src, ms-href)19. 万能属性绑定(ms-attr)20. 万能绑定(ms-bind)21. 循环绑定(ms-each)22. UI绑定(ms-ui)23. $watch24. 过滤器25. AMD加载器关于AvalonJSavalon是一个迷你的MVVM框架,虽然从发布到现在,它臌胀了不少,但它现在还是比knockout小许多。avalon开发过程一直遵循三个原则:1,复杂即错误,2,数据结构优于算法,3,出奇制胜。这三大原则保证avalon具有良好的维护性,扩展性,与众不同。简单说一下其他三大MVVM的实现思路:1. knockout:最早冒出来的JS MVVM库,通过转换VM中所有要监听的东西为函数,然后执行它们,得到某一时刻中,一共有多少函数被执行,将它们放到栈中,最底的就是最先被执行的,它上面的就是此函数所依赖的函数,从而得到依赖关系。 然后设计一个观察者模式,从上面的依赖检测中,将依赖函数作为被依赖者(最先执行的那个的)的订阅者,以后我们对被依赖者进行赋值时,就会通先订阅者更新自身,从而形成一个双向绑定链。 并且,knockout会将视图中的绑定属性进行转换,分解出求值函数与视图刷新函数,视图刷新函数依赖于求值函数,而求值函数亦依赖于我们VM中的某些属性(这时,它们都转换为函数),在第一次扫描时,它们会加入对应属性的订阅者列队中, 从而VM中的某个属性改变,就会自动刷新视图。评价:实现非常巧妙,是avalon0.1-0.3的重要学习对象,但将属性变成一个函数,让人用点不习惯,许多用法都有点笨笨的。 虽然是一个轻盈的库,但扩展性不强,里面的实现异常复杂,导致能参与源码的人太少。2. emberjs: 一个大而全的框架,包罗万象。一开始是使用Object.defineProperty+观察者实现,但IE8的问题,让它不得不启用上帝setter, 上帝getter。没有自动收集依赖的机制,没有监控数组,计算属性需要自己指定依赖。VM可继承。 VM与视图的双向绑定依赖于其强大无比上万行的Handlebars 模板。听说是外国目前最好用的MV*框架。因为作者既是jQuery的核心成员,也是Rails的核心成员,虽然由于技术能力没实现自动收集依赖,但框架的其他方面做得非常易上手,人性化。评价:太大了,优缺点同python的Django框架。3. angular: google组织开发的框架,体现其算法至上的时候到了。里面一共有两个parser, 一个是ngSanitize/sanitize.js下的HTML parser, 一个是ng/parse.js(它要配合compile.js使用)的JS parser。第一个parser负责绑定抽取,第二个负责从Ctrl函数,工厂函数,服务函数及$watch回调中分解出无数setter, getter, 确认它们的依赖关系,放进观察者模式中。它的观察者无比强大,由于它的VM能继承,于是通过继承链实现四通发达的消息广播。它还实现了一个基于LRU的缓存系统,因为google最喜欢以空间换时间了,另一方面说明它要缓存的东西太多了,非常吃内存。 公司内部用angular实现的grid,200行在PC中就拖不动了。它还用到许多时髦的东东,如HTML5 history API, 迷你版Q Promise。内部是极其复杂。 不过最大的问题是,它是基于parser,静态编译,这意思着什么呢?不抗压缩!为此,它引进了IOC,官网上给出的简单例子其实在项目完全不可用,我们需要使用另一种更复杂的写法,方便编泽器从它们得到不被压缩的部分, 让它在压缩情况也能正常运行。由于基于编译,许多行为都不是即时的,可预见的。用户写的那些控制器函数,都是为编译做准备。由于基于编译,它不得不要求我们对具有兼容问题的一些全局函数,方法进行屏蔽,用它的给出的服务替代它们,如 window对应$window, document对应$document, location对应$location, setTimout对应$timeout如果不遵循这规则,它可能运行不了,你需要手动使用$digest手动触发。不过,它与emberjs一样,走大而全的道路,连测试框架也有了,并且由于是MVVM,因此比起其他框架易写测试。评价:上手难度非常大,没有想象中的好用。有句话是这样说的,Backbone像是穿救生衣游泳,你要自己游到对岸去,Angular像是开快艇,但是没有救生衣。现在的avalon是我在完全消化了knockout发展起来的,准确来说,是0.4版,通过Object.defineProperties与VBScript实现了与普通对象看起来没什么两样的VM,VM里面充满了访问器属性,而访问器属性肯定对应一个setter,一个getter, 我们就在setter, getter中走knockout的老路,实现自动收集依赖,然后放进一个简单的观察者模式中,从而实现双向绑定。将绑定属性分解为求值函数与视图刷新函数,早前,avalon也与knockout一样使用一个简单的parser,然后通过with实现, 0.82一个新的parser 上马,同样的迷你,但生成的求值函数,更方便依赖收集,并且没有with语句,性能更佳。angular也不是一无是处,我也从它那里抄来了插值表达式,过滤器机制,控制器绑定什么的。avalon在内部使用了许多巧妙的设计,因此能涵盖angular绝对大多数功能,但体积却非常少。此外,在性能上,现在除了chrome外,它都比knockout快,angular则是最慢的。 在移动端上,avalon这个优势会被大大放大化的。关于avalon的几点: 兼容IE6 没有AJAX与动画模块,需要配合jQuery等库使用 avalon会自动同步视图,因此不要在VM中进行DOM操作迷你MVVM框架在github的仓库/RubyLouvre/avalon, 如果你要兼容IE6,那么下其中的avalon.js, 如果你只打算兼容IE10与标准浏览器,那么下avalon.mobile.js。官网地址http:/rubylouvre.github.io/mvvm/大家可以加入QQ群:79641290进行讨论,此群为技术群,禁水!开始的例子我们从一个完整的例子开始认识 avalon :htmlview plaincopyprint?1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. wxh12. W:13. H:14. 15. 16. avalon.define(box,function(vm)17. vm.w=100;18. vm.h=100;19. vm.click=function()20. vm.w=parseFloat(vm.w)+10;21. vm.h=parseFloat(vm.h)+10;22. 23. )24. 25. 26. 27. 28. 上面的代码中,我们可以看到在JS中,没有任何一行操作DOM的代码,也没有选择器,非常干净。在HTML中, 我们发现就是多了一些以ms-开始的绑定属性与插值表达式,有的是用于渲染样式, 有的是用于绑定事件。在ms-model中,我们会发现它会反过来操作VM,VM的改变也会影响视图的其他部分。扫描不过上面的代码并不完整,它能工作,是因为框架默认会在DOMReady时扫描DOM树,将视图中的绑定属性与插值表达式抽取出来,转换为求值函数与视图刷新函数。我们可以通过下面方法自己扫描DOM树:jsview plaincopyprint?1. avalon.ready(function()2. avalon.define(box,function(vm)3. vm.w=100;4. vm.h=100;5. vm.click=function()6. vm.w=parseInt(vm.w)+10;7. vm.h=parseInt(vm.h)+10;8. 9. )10. avalon.scan()11. )scan有两个可选参数,第一个是扫描的起点元素,默认是HTML标签,第2个是VM对象。jsview plaincopyprint?1. /源码2. avalon.scan=function(elem,vmodel)3. elem=elem|root4. varvmodels=vmodel?.concat(vmodel):5. scanTag(elem,vmodels)6. 7. 视图模型我们是通过avalon.define函数返回一个视图对象VM,并且avalon.define(vmName, function(vm)中的vm并不等于VM,工厂函数中的vm是用于转换为VM的。生成的VM比用户指定的属性还多了许多属性。默认的,除了函数外,其他东西都转换为监控属性,计算属性与监控数组。如果不想让它转换,可以让此属性以 $开头,框架就不会转换它们。如果实在不放便改名,又不想被转换,比如是一个jQuery对象或一个DOM节点,如果转换,肯定拖死框架,我们可以放到vm.$skipArray = propName1, propName2中去,这样也忽略转换。另外,avalon不允许在VM定义之后,再追加新属性与方法,比如下面的方式是错误的: var vm = avalon.define(test, function(vm) vm.test1 = 点击测试按钮没反应 绑定失败; ); vm.one = function() vm.test1 = 绑定成功; ; /这里有两个错误, /1在命名上没有区分avalon.define的返回值与它回调中的参数, /2one方法的定义位置不对(这是考虑到兼容IE6-8,要求所有浏览器保持行为一致) 数据模型当我们要用AJAX与后端交互时,如果直接把VM传上去太大了,这时我们需要把它对应的纯数组的JS对象。在VM中有个叫$model的属性,这是一个对象,就是数据模型M了。当我们更改VM时,框架就会自动同步M绑定属性与动态模板在开始之前,我们看一下静态模板是怎么工作的:我之前写了一个叫ejs的静态模板引擎:htmlview plaincopyprint?1. 2. 3. 4. &-for(vari=0,tl=trs.length,tr;i5. 6. 7. 8. 9. 10. 11. 6. vm.click=function()7. vm.a=newDate-08. 9. )10. 最后要注意的是,HTML5已经规定,特性节点的名字只能小写,因此什么ms-ui-xxx, 都要小写化!这是浏览器行为,无可奈何。作用域绑定(ms-controller, ms-important)avalon提供ms-controller, ms-important来指定VM在视图的作用范围。比如有两个VM,它们都有一个firstName属性,在DIV中,如果我们用 ms-controller=VM1, 那么对于DIV里面的firstName就会解析成VM1的firstName中的值。有关它们的详细用法,可见这里。模板绑定(ms-include)如果单是把DOM树作为一个模板远远不够的,比如有几个地方,需要重复利用一套HTML结构,这就要用到内部模板或外部模板了。内部模板是,这个模板与目标节点是位于同一个DOM树中。我们用一个MIME不明的script保存它,然后通过ms-include=id引用它。htmlview plaincopyprint?1. 2. here,1+13. 4. 5. 注意,ms-include的值要用引号括起,表示这只是一个字符串,这时它就会搜索页面的具有此ID的节点,取其innerHTML,放进ms-include所在的元素内部。否则这个tpl会被当成一个变量, 框架就会在VM中检测有没有此属性,有就取其值,重复上面的步骤。如果成功,页面会出现here, 2的字样。外部模板,通常用于多个页面的复用,因此需要整成一个独立的文件。这时我们就需要通过ms-include-src=src进行加载。比如有一个HTML文件tmpl.html,它的内容为:htmlview plaincopyprint?1. 这是一个独立的页面2. 它是通过AJAX的GET请求加载下来的3. 然后我们这样引入它htmlview plaincopyprint?1. 数据填充(ms-text, ms-html)这分两种:文本绑定与HTML绑定,每种都有两个实现方式htmlview plaincopyprint?1. 2. 3. avalon.define(test,function(vm)4. vm.text=11115. )6. 7. 8. 9. 用于测试是否被测除xxxxtextyyyy10. 用于测试是否被测除xxxxtext|htmlyyyy11. 用于测试是否被测除xxxxyyyy12. 用于测试是否被测除xxxxyyyy13. 类名切换(ms-class, ms-hover, ms-active)avalon提供了多种方式来绑定类名,有ms-class, ms-hover, ms-active, 具体可看这里事件绑定(ms-on)avalon通过ms-on-click或ms-click进行事件绑定,并在IE对事件对象进行修复,并统一了所有浏览器对return false的处理。具体可看这里avalon并没有像jQuery设计一个近九百行的事件系统,连事件回调的执行顺序都进行修复(IE6-8,attachEvent添加的回调在执行时并没有按先入先出的顺序执行),只是很薄的一层封装,因此性能很高。 ms-click ms-dblclick ms-mouseout ms-mouseover ms-mousemove ms-mouseenter ms-mouseleave ms-mouseup ms-mousedown ms-keypress ms-keyup ms-keydown ms-focus ms-blur ms-change ms-on-*显示绑定(ms-visible)avalon通过ms-visible=bool实现对某个元素显示隐藏控制,对于低版本的浏览器,它用的是style.display=none进行隐藏,对于支持HTML5的浏览器,它是使用hidden属性来控制。因此它是优于其他MVVM的实现。插入绑定(ms-if)这个功能是抄自knockout的,ms-if=bool,同样隐藏,但它是将元素移出DOM。这个功能直接影响到CSS :empty伪类的渲染结果,因此比较有用。双工绑定(ms-duplex)这功能抄自angular,原名ms-model起不得太好,姑且认为利用VM中的某些属性对表单元素进行双向绑定。打算启用一个新名字叫ms-duplex这个绑定,它除了负责将VM中对应的值放到表单元素的value中,还对元素偷偷绑定一些事件,用于监听用户的输入从而自动刷新VM。具体如下:text, password, textarea默认是通过input事件进行监听,旧式IE是通过propertychange实现,换言之,每改一个字符串都触发。如果想在失去焦点时才触发,可以在元素上使用data-event=change进行调整。 它要求VM对应的属性为一个字符串或数字,不过触发一次之后,属性就会变成字符串。radio默认是通过change事件进行监听,旧式IE是通过chick实现, 它要求VM对应的属性为一个布尔。checkbox默认是通过change事件进行监听, 它要求VM对应的属性为一个字符串数组。select默认是通过change事件进行监听, 它要求VM对应的属性为一个字符串或字符串数组(视multiple的值)。样式绑定(ms-css)用法为ms-css-name=valuejsview plaincopyprint?1. 2. 3. 数据绑定(ms-data)用法为ms-data-name=value, 用于为元素节点绑定HTML5 data-*属性。布尔属性绑定这主要涉及到表单元素几个非常重要的布尔属性,即disabed, readyOnly, selected , checked, 分别使用ms-disabled, ms-enabled, ms-readonly, ms-checked, ms-selected。ms-disabled与ms-enabled是对立的,一个true为添加属性,另一个true为移除属性。字符串属性绑定这主要涉及到几个非常常用的字符串属性,即href, src, alt, title, value, 分别使用ms-href, ms-src, ms-alt, ms-title, ms-value。它们的值的解析情况与其他绑定不一样,如果值没有插值表达式,那么就当成VM中的一个属性,并且可以与加号,减号混用, 组成表达式,如果里面有表达式,整个当成一个字符串。jsview plaincopyprint?1. xxxx2. xxxx万能属性绑定(ms-attr)ms-attr-name=value,这个允许我们在元素上绑定更多种类的属性,如className, tabIndex, name, colSpan什么的。万能绑定(ms-bind)ms-bind是一种非常强大的同步机制,因为它允许你持续监听某一个VM属性的变化,并且它的参数是一个函数,this又是指向绑定属性的元素节点,因此比ms-css, ms-attr, ms-data, ms-click等有着因定DOM操作的绑定来得更灵活。用法: ms-bind-prop=callback, 其中prop, callback都要求来自同一个VM。callback为一个函数,this指向元素节点。htmlview plaincopyprint?1. 2. 3. 点我4. 5. 6. jsview plaincopyprint?1. avalon.define(test,function(vm)2. vm.aaa=1111;3. vm.callback=function()4. this.innerHTML=vm.aaa5. 6. vm.one=function()7. vm.aaa=newDate-08. 9. );10. 循环绑定(ms-each)用法为ms-each-xxx=array, 其中xxx可以随意改,如yyy, el, 它是用于在子元素中进行引用。array对应VM中的一个普通数组或一个监控数组。详见这里。htmlview plaincopyprint?1. 2. avalon.define(test,function(vm)3. vm.array=value:aaa,text:111,value:bbb,text:222,value:bbb,text:3334. )5. 6. 7. 8. $index、el9. 10. UI绑定(ms-ui)它的格式为ms-ui-$opts=uiName, 其他$opts可有可无,存在时对应VM中的一个对象,建议将它设置为不可监控的,因为它只是作为一个配置对象。uiName为控件的名字。此外,在绑定元素上还应该设置一个data-id属性,用于指定生成的UI控件对应的VM的名字。你也可以设置更多的data-*属性,方便用于配置UI。下面是一个完整的实例用于教导你如何定义使用一个UI。例子首先,以AMD规范定义一个模块,文件名为avalon.testui.js,把它放到与avalon.js同一目录下。内容为:jsview plaincopyprint?1. define(avalon,function(av)2. /UI控件的模板3. /必须在avalon.ui上注册一个函数,它有四个参数,最后一个是可选的,其他分别为容器元素,VM的ID名,vmodels4. av.uitestui=function(element,id,vmodels,opts)5. opts=opts|6. varmodel=av.define(id,function(vm)7. =这是控件的默认内容8. )9. for(variinopts)10. if(model.hasOwnProperty(i)/必须要用hasProperty,因为model在IE6-8为一个VBS对象,不允许添加新属性11. modeli=optsi12. 13. 14. /必须在nextTick的回调里插入新节点与进行扫描15. av.nextTick(function()16. element.innerHTML=name17. /这里的格式是固定的18. av.scan(element,model.concat(vmodels)19. )20. returnmodel/这里必须返回VM对象,好让avalon.bindingHandlers.ui方法,将它放到avalon.vmodels中21. 22. returnav/必须有返回值23. )24. 25. 26. 然后页面这样使用它htmlview plaincopyprint?1. 2. 3. require(avalon.testui,function()4. avalon.define(test,function(vm)5. vm.$opts=6. name:这是控件的内容7. 8. )9. avalon.scan()10. console.log(avalon.vmodels.ddd)11. )12. 13. 14. 15. 16. 17. 18. $watch这是一个位于VM的方法,用于监听VM的某人属性的变化,回调中有两个传参,新属性值与旧属性值,里面的this指向VM,详见这里。过滤器avalon从angular中抄来管道符风格的过滤器,但有点不一样。 它只能用于插值表达式。如果不存在参数,要求直接跟|filter,如果存在参传,则要用小括号括起,参数要有逗号,这与一般的函数调用差不多,如|truncate(20,)avalon自带以下几个过滤器html没有传参,用于将文本绑定转换为HTML绑定uppercase大写化lowercase小写化truncate对长字符串进行截短,truncate(number, truncation), number默认为30,truncation为“.”camelize驼峰化处理escape对类似于HTML格式的字符串进行转义,把尖括号转换为> <currency对数字添加货币符号,以及千位符, currency(symbol)number对数字进行各种格式化,这与与PHP的number_format完全兼容, number(decimals, dec_point, thousands_sep), decimals可选,规定多少个小数位。 dec_point可选,规定用作小数点的字符串(默认为 . )。 thousands_sep可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。 date对日期进行格式化,date(formats)htmlview plaincopyprint?1. yyyy:4digitrepresentationofyear(e.g.AD1=0001,AD2010=2010)2. yy:2digitrepresentationofyear,padded(00-99).(e.g.AD2001=01,AD2010=10)3. y:1digitrepresentationofyear,e.g.(AD1=1,AD199=199)4. MMMM:Monthinyear(January-December)5. MMM:Monthinyear(Jan-Dec)6. MM:Monthinyear,padded(01-12)7. M:Monthinyear(1-12)8. dd:Dayinmonth,padded(01-31)9. d:Dayinmonth(1-31)10. EEEE:DayinWeek,(Sunday-Saturday)11. EEE:DayinWeek,(Sun-Sat)12. HH:Hourinday,padded(00-23)13. H:Hourinday(0-23)14. hh:Hourinam/pm,padded(01-12)15. h:Hourinam/pm,(1-12)16. mm:Minuteinhour,padded(00-59)17. m:Minuteinhour(0-59)18. ss:Secondinminute,padded(00-59)19. s:Secondinminute(0-59)20. a:am/pmmarker21. Z:4digit(+sign)representationofthetimezoneoffset(-1200-+1200)22. formatstringcanalsobeoneofthefollowingpredefinedlocalizableformats:23. 24. medium:equivalenttoMMMd,yh:mm:ssaforen_USlocale(e.g.Sep3,201012:05:08pm)25. short:equivalenttoM/d/yyh:mmaforen_USlocale(e.g.9/3/1012:05pm)26. fullDate:equivalenttoEEEE,MMMMd,yforen_USlocale(e.g.Friday,September3,2010)27. longDate:equivalenttoMMMMd,yforen_USlocale(e.g.September3,201028. mediumDate:equivalenttoMMMd,yforen_USlocale(e.g.Sep3,2010)29. shortDate:equivalenttoM/d/yyforen_USlocale(e.g.9/3/10)30. mediumTime:equivalenttoh:mm:ssaforen_USlocale(e.g.12:05:08pm)31. shortTime:equivalenttoh:mmaforen_USlocale(e.g.12:05pm)32. 例子:生成于 new Date | date(yyyy MM dd:HH:mm:ss)生成于 2011/07/08 | date(yyyy MM dd:HH:mm:ss)生成于 2011-07-08 | date(yyyy MM dd:HH:mm:ss)生成于 01-01-2000 | date(yyyy MM dd:HH:mm:ss)生成于 03 04,2000 | date(yyyy MM dd:HH:mm:ss)生成于 3 4,2000 | date(yyyy MM dd:HH:mm:ss)生成于 1373021259229 | date(yyyy MM dd:HH:mm:ss)生成于 1373021259229 | date(yyyy MM dd:HH:mm:ss)值得注意的是,new Date可传的格式类型非常多,但不是所有浏览器都支持这么多,详看这里多个过滤器一起工作htmlview plaincopyprint?1. prop|filter1|filter2|filter3(args,args2)|filter4(args)如果想自定义过滤器,可以这样做jsview plaincopyprint?1. avalon.filters.myfilter=function(str,args,args2)/str为管道符之前计算得到的结果,默认框架会帮你传入,此方法必须返回一个值2. /*具体逻辑*/3. returnret;4. AMD 加载器avalon装备了AMD模范的加载咕咕,这涉及到两个全局方法 require与definerequire(deps, callback)deps 必需。String|Array。依赖列表,可以是具体路径或模块标识,如果想用字符串表示多个模块,则请用“,”隔开它们。callback 必需。Function。回调,当用户指定的依赖以及这些依赖的依赖树都加载执行完毕后,才会安全执行它。模块标识一个模块标识就是一个字符串,通过它们来转换成到对应JS文件或CSS文件的路径。有关模块标识的CommonJS规范,可以见这里具体约定如下:1. 每个模块标识的字符串组成只能是合法URL路径,因此只能是英文字母,数字,点号,斜扛,#号。2. 如

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论