大半年前我就说过,MVVM是前端究极的解决方案,因此之后我大多数时间都在折腾avalon,成立了专门的QQ群与感兴趣的一起讨论。感谢第一批吃螃蟹的人,avalon发展得很快,GITHUB上的贡献人数达到8人,issues二百多个主题,各种组件也不断完善。时至今日,我可以自豪地说许多静待1.0的看客说,它终于来了!

下面是avalon的生态系统:

avalon的核心是avalon.js或avalon.mobile.js(移动端版本,针对手机与平板)。其中avalon.js兼容到IE6,满足中国的特殊国情。avalon.mobile.js是支持移动端,IE10起支持,它使用了大量高级API,性能远超avalon.js,并添加了触屏事件的支持。

然后是三柱臣:mmRouter, mmAnimate, mmRequest,单页应用最常用的三个组件。

接着是拖放,事件代理,组件键,验证框架,高级定位机制,组合键等乱七八糟的,用于锦上添花的

最后是UI库,比较简单的控件都做出来,重头的树,GRID,多级菜单正在规划中……

说一下我的初衷啊。我最早是做企业级应用,大量的表单,大量的列表,迭代频繁,虽然JQ已经出来了,但业务逻辑与DOM显示逻辑混淆在一起,维护起来非常不爽。于是我开发了ejs这个前端模板。前端模板在当前还是一个很新的概念,因此我当时发布在博客园,许多人不解。但比起在JS文件里进行锁碎的字符串拼接,它就是易读易维护。QQ空间,淘宝那时也已经使用前端模板了。那是09年的事。之后,前端模板就像雨后春笋地不断涌现,性能越来越高。

转辗到盛大创新院后,做圈乐这个视频项目的瀑布流,与大牛们共事,用的是qwrap,接触了许多新概念。我的框架由dom Framework更名mass Framework,大量精力耗在选择器引擎与模块加载器的开发上。那时requirejs也是刚刚起步, Sizzle也很粗糙,因此这两个领域都有大量同类型产品。我大量读库,实力蒸蒸日上。创新院大裁员,我避风到SDO做盛大通行证,我深切地体会到现行开发模式的掣肘之处。我在创新院还可以用前端模板搞定渲染问题,但这是一对一的。盛大通行证一个逻辑面向不同的视图,要求务业逻辑与DOM渲染逻辑彻底分离,要不没法进行下去。当时我只有求助于JAVA的设计模式,各种解耦。像后端spring,早已想到这一点,因此才有IoC容器这样的东西出来。在处理渲染方面,它们有庞大的标签库,这是面向组件开发的拓路者。为了更好的控制标签的行为,微软从MVC的基础上发展起MVVM。MVVM用尽了23种设计模式,让我们轻松地操作一个叫VM的特殊数据源就能自动同步视图,这种机制被称之为绑定。绑定在微软的体系中分为三种one way, one time, two way。微软出身的Steve Sanderson搞出了第一个前端MVVM框架knockout。当时,09年,别说MVVM,MVC在前端也是新事物。前端MVC的风头从jQueryMVC转到backbone。我的注意力也停留在backbone身上。backbone有着后端JAVA MVC框架的优缺点,分类极细,责任明晰,但这也意味着繁锁,定义了许多类,但好像又什么也没干。其中这当中的类可以由框架自动生成。

模块加载器开发了十多个版本号, 我着手开发UI库了。这时愈感JQ的不便。UI是一种界面,很早以前人们就发现,干这活是声明式语言的强项。我们平时熟悉的javascript, C, C++, java则擅长做逻辑。于是才有前端模板这东西,将数据源往模板一套,界面就出来的。但之前的模板都属于字符串模板,无法对生成的元素节点进行后继操作。不过,据元素节点的innerHTML的能耐来看,它也不执行里面的script脚本。jquery的html可以打破这桎梏,其实也基于eval处理的。最终,knockout还是走入我的视野。很大一个原因是我一直活跃于博客园,博客园属于微软系,微软这个东西虽然难用一点,但在当时也算是至宝!

knockout是一个伟大的框架,一直很低调。作者是后端的人,很JS用得炉火纯青,大量的闭包,加之方法名,变量名是找C#那一套,名字巨长,搞得很难读懂它的源码。knockout的思想很简单,把用户的操作分成两部分,赋值与取值。赋值时,它就想办法同步视图。取值时,它就试图取得各种操作的依赖关系。有了依赖关系,就可以构成观察者模式,让视图同步成为可能。为了达到这目的,必须让框架知道当前进行的是什么操作,操作的作用方是谁。由于当时javascript访问器属性还鲜为人知,在旧式IE也有兼容难题。knockout取采的策略是将所有属性都转换为函数,根据函数有没有传参就可以辨识用户的行为了。对于数组,它是重写所有原生方法。avalon0.1-0.3就是追随knockout的步伐,逐渐了解它的其他概念与实现原理。比如说计算属性,取值属性,视图刷新函数,各种常用的绑定。

我之前谈如何写框架,就提到三个原则:复杂即错误,数据结构优于算法,出奇制胜。knockout的源码太复杂,导致想参与的人参与不进来。为了降低上手难度,你无论是从接口到实现,一定要条理清晰,不能到处是黑魔法与飞线方案。虽然avalon的源码只有一个文件,里面的条理是非常清晰的,并且刻意使用一些特殊的注释来隔开各个功能区。API尽可能少,许多重要的接口都不暴露出来,以后就可以随意折腾,不影响用户使用了。在厘清knockout的实现机理后,我就是由单纯的做轮子,转为发明新轮子。首先,属性转换为函数这一用法必须去掉,太扭曲了。ember的做法是使用两个上帝set, get方法来接管一切取值赋值操作,比knouckout好多了,但依然不直观。angular是直接对控制器等函数取toString进行编译,用法简单了,但实现难度非常高,加之它其余设计把这易用性泯灭了。于是我转来转去,还是求助于访问器属性解决了。这过程不是三言两语说得清的,但从结果来看,就是Object.defineProperties与VBScript类的Set, Get, Let语法。用户传入一个对象,然后我转出另一个跟它非常相似,好像只是添加了几个属性的对象,然后用户对它的属性进行操作,它就能同步视图,相当fantasy、 magic!易用性爆表了!

其次是绑定属性的设计, knockout是使用data-bind对应一个没有两端花括号的JSON对象字符串,看似规整划一,但这意味着内部要实现一个parser来转换。后起之秀的angular则友好多了,但最终我是参照了rivetsjs。缘由它的绑定风格能提供更多信息,更易分解,用户也很易理解。这样我就不用耗时实现一个庞大易出错的parser了。编码不同于建筑,BUG与规模是成比例增长,控制代码量是avalon在编写过程的一个重要指标,至少它还没有超过4000行。

最后根据用户的反馈,不断增加新功能,在增加新功能时不断引入BUG,然后修BUG,改好了,发现性能下降,于是提高性能。性能提高了,用户又提出新功能,然后……周而复始,不断与需求与BUG作斗争。这就像一个普通的产品的开发流程。不同的是,这个产品完全是属性于你,你有杀生大权,你能完全享受用户对你的赞誉。但反过来,其实我还是得感谢那些敢吃螃蟹的人,那些提BUG的人,那些pull request的人。正因为,这项目比mass Framework发展得顺利多了。它与最初的第一版几乎没有一行相同的代码,尽管我尽量避免API的改动,API最后也有改动了,变得更加精巧。

0.4-0.7是脱胎换骨时期,它一直留在mass Framework项目的内部。0.72独立出来,可以独挡一面了。这时不断改进绑定的实现,一直到0.94才稳定下来。难点在于ms-each, ms-repeat, ms-with, ms-widget(ms-ui), ms-if这五种API。它们的特点都是有节点插入操作。有的是插入了移除,移除了插入, 有的是循环生成一堆相同节点,有的是按照一个模板生成一个控件。由于绑定都有生命周期的概念,它的实现方式直接与它是否在DOM树挂钩,但如何是框架自己临时移出DOM树呢,于是就引发一系列问题了。幸好最终都解决了。这基本是靠时间磨出来的,今天想不出来,睡一觉明天就想通一点点,后天又解决一点点……

facebook实现一个react的MVVM框架,炒作一个叫反应式编程的概念。其实它的核心就是knockout的弱化版。对我看来,用数学的自变量,因变量来表达它们之间的关系更适合。其中绑定属性,监控数组的方法就是自变量,这是由用户直接操作的。计算属性,求值函数,视图刷新函数就是因变量,由下层的绑定属性,数组方法所驱动。0.99起,开始大量性能优化,把求值函数,视图刷新函数都共享了。但这些东西,用户根本不需要知道,说不定某天发现更高效的实现方式,它们就不存在了。所有要注意之处,在《入门教程》已经标明。要深入可以看《最佳实践》。再者看源码,这些概念只是辅助你看当前版本的源码。想成为高手,还是从源码着手。只是想快速完成任务,看我的《入门教程》就够了。

感谢这个时代,正因为有了IE6才有我们前端,正因为有前端才有我们这些民科外行沾光IT的福利。

迷你MVVM框架在github的仓库https://github.com/RubyLouvre/avalon

官网地址http://rubylouvre.github.io/mvvm/

有关avalon的最佳实践或注意点请看这里, 这个我每次发布新版本都可能在这里加东西


1.0的相关改进

  • 优化executeBindings, 插值表达式形式的文本绑定不需要removeAttribute
  • 优化scanText, 它生成的绑定属性不需要element元素
  • fix duplex 绑定, 从左到右检测匹配的vmodel
  • duplex 绑定添加表单检证的钩子
  • 优化监控数组的sort, reverse方法
  • avalon.fn.css支持设置多个属性,优化旧式IE下的取宽高
  • 重构ms-widget, 过滤中间生成的VM, 支持在配置对象里指定ID
  • 重构fixEvent
  • fix ms-class BUG
  • 优化nextTick
  • 为性能考量,弱化avalon.Array.ensure
  • 移除data.remove属性,通过是否存在求值函数evaluator来移除绑定属性
  • 共享所有视图刷新函数
  • clearChild 更名为 clearHTML
  • IE67下添加getAttributes方法,直接使用正则抽取绑定属性

朋友们用avalon做的东西

未来avalon的发展方向就是三大重型UI组件:树,GRID,多级菜单。望大家也多多贡献,一起完善这个生态圈。

2013年最后的收成:avalon1.0正式发布的更多相关文章

  1. avalon1.0正式发布

    2013年最后的收成:avalon1.0正式发布 大半年前我就说过,MVVM是前端究极的解决方案,因此之后我大多数时间都在折腾avalon,成立了专门的QQ群与感兴趣的一起讨论.感谢第一批吃螃蟹的人, ...

  2. AppBox_v2.0完整版免费下载,暨AppBox_v3.0正式发布!

    文章更新: AppBox v6.0中实现子页面和父页面的复杂交互 AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. AppBox ...

  3. Socket.IO 1.0 正式发布,快速可靠的实时引擎

    Socket.IO 是目前 Web 领域最火的实时引擎,用于实现基于事件的双向实时的通信.它适用于任何平台,浏览器或设备,专注于可靠性和速度.您可以将数据推送到客户端,并获得实时的计数,日志或图表. ...

  4. Django 1.6.0 正式发布,大幅改进事务处理

    Django 1.6.0 正式发布了,查看官方发行说明. 下载地址:Django-1.6.tar.gz ,也可通过 pip 安装: pip install Django==1.6 要求 Python ...

  5. Apache Spark2.0正式发布

    Apache Spark2.0正式发布 7月26日起Databricks开始提供Apache Spark 2.0的下载,这个版本是基于社区在过去两年的经验总结而成,不但加入了用户喜爱的功能,也修复了之 ...

  6. 【G-BLASTN 1.0正式发布】

    [G-BLASTN 1.0正式发布]G-BLASTN使用GPU来加速NCBI-BLAST里的BLASTN模块,单块GTX780比四核CPU平均快6倍. http://www.comp.hkbu.edu ...

  7. Angular4.0.0正式发布,附新特性及升级指南

    本文首发地址:Angular4.0.0正式发布,附新特性及升级指南 作者|孙薇 编辑|尾尾 经历了6个RC版本之后,Angular项目组终于发布了新版,即正式版 Angular 4.0.0.新版的 A ...

  8. 重磅:Spring Boot 2.0 正式发布!

    Spring Boot 2.0 正式发布! 2018/03/01最新消息,传得沸沸扬扬的Spring Boot 2.0 正式发布了. 小编去看了下Spring Boot的官网,正式版本已经释放出来了! ...

  9. Spring Boot 2.0正式发布,新特性解读

    作者|翟永超 Spring Boot 2.0 来啦,有哪些新特性?升级吗? 写在前面 北京时间 3 月 1 日,经过漫长的等待之后,Spring Boot 2.0 正式发布.作为 Spring 生态中 ...

随机推荐

  1. SpringMvc中的Interceptor拦截器的学习

    拦截器是SpringMvc框架中常用的一个东东,它跟Filter相似,但是也有区别,以前也没用过,今天看到就顺便学习了一下. SpirngMvc中的Interceptor主要是通过HandlerInt ...

  2. URL 生成带文字二维码

    <!DOCTYPE html> <html> <head> <title></title> <meta charset="u ...

  3. 重新学习之spring第二个程序,配置AOP面向切面编程

    第一步:在配置好的ioc容器的基础上,导入面向切面编程所需要的jar包 (本案例用的是spring3.2.4,由于spring3.2.4的官网jar包中不再有依赖包,所以依赖包都是从网上找的) 第二步 ...

  4. cratedb 集群搭建说明

    此为搭建说明,实际上搭建过es 集群的都是可以的,和es 基本一样 配置文件 crate.yaml 参考集群架构图 集群名称 cluster.name: my_cluster 每个node节点名称 如 ...

  5. IMP-00009: 导出文件异常结束 imp

    在一次exp/imp中,用imp导入数据时报错.错误信息如下: IMP-00009: 导出文件异常结束 imp导入时异常结束可以有很多原因造成,要具体问题具体分析. 可能原因一: 导入的数据表过大,而 ...

  6. highlight.js 设置行号

    原文地址:highlight.js 设置行号 博客地址:http://www.extlight.com 一.背景 笔者在开发这套博客系统时使用 Editormd 作为 Markdown 编辑器,由于不 ...

  7. laravel Hash密码 校对

    laravel加密 是使用hash不可逆的,但是可以对加密后的密码进行校对 $data = $r->all();$id = $data['id'];$user_password = bcrypt ...

  8. 02 - Unit07:显示笔记下拉菜单、笔记的分享功能、笔记的删除功能

    显示笔记下拉菜单 笔记的分享功能 发送Ajax请求 绑定事件:绑定分享按钮单击事件 参数获取:笔记ID 发送请求:/share/add.do 服务器处理 ShareController ShareSe ...

  9. 异步FIFO中空满信号如何产生?

    异步FIFO中,空满信号该如何产生呢? 在复位的时候,读指针和写指针相等,读空信号有效(这里所说的指针其实就是读地址.写地址)当读指针赶上写指针的时候,写指针等于读指针意味着最后一个数据被读完,此时读 ...

  10. 解决标准FPGA资源丰富却浪费的问题

    FPGA以计算速度快.资源丰富.可编程著称,之前一直应用于高速数字信号领域和ASIC验证.随着逻辑资源的丰富和编程工具的改进,FPGA在机器学习和硬件加速上得到越来越多的重视,目前数据中心已经大量采用 ...