/avalon

a lightweight、high-performance and easy-to-follow javascript MVVM framework

Primary LanguageJavaScript

Avalon

迷你简单易用的MVVM框架

前端做久了就会发现HTML(DOM)才是所有前端的真正精髓汇聚地。不管JS和CSS都是为DOM服务的。但是DOM遍布荆棘与陷阱,因此才出现像jQuery那样专门为它填坑的库, 当下的前端开发就是一边填坑一边写业务中进行。avalon的诞生改变了这一切,让我们摆脱DOM的掣肘,专注于需求本身,将可变的数据与操作数据的方法封装成模型。 在更高的层次上组织代码,提高软件的可维护性,可扩展性和可重用性。


  • avalon现在有三个分支:avalon.js 兼容IE6,标准浏览器, 及主流山寨浏览器(QQ, 猎豹, 搜狗, 360, 傲游); avalon.modern.js 则只支持IE10等支持HTML5现代浏览器 ; avalon.mobile.js,添加了触屏事件与fastclick支持,用于移动端;
  • avalon拥有强大的组件库,现在由去哪儿网前端架构组在维护与升级,这里;首先是三柱臣,想使用路由器,可以用mmRouter, 想使用动画,可以用mmAnimate, 想使用AJAX,可以用mmRequest; 其是是OniUI,树组件差不多开发完毕,届时就有一个拥有2个Grid,1个树,1 个验证插件等总数近50个UI组件的库了。
  • avalon的测试比较庞大,放在独立的仓库中——avalon.test

优势

绝对的优势就是降低了耦合, 让开发者从复杂的各种事件中挣脱出来. 举一个简单地例子, 
同一个状态可能跟若干个事件的发生顺序与发生时的附加参数都有关系, 
不用 MVC (包括 MVVM) 的情况下, 逻辑可能非常复杂而且脆弱. 
并且通常需要在不同的地方维护相关度非常高的一些逻辑, 
稍有疏忽就会酿成 bug 不能自拔. 使用这类框架能从根本上降低应用开发的逻辑难度, 并且让应用更稳健.

除此之外, 也免去了一些重复的体力劳动, 一个 {value} 就代替了一行 $(selector).text(value),
一些个常用的 directive 也能快速实现一些原本可能需要较多代码才能实现的功能
  • 使用简单,在HTML中添加绑定,在JS中用avalon.define定义ViewModel,再调用avalon.scan方法,它就能动了!
  • 兼容到 IE6 (其他MVVM框架,KnockoutJS(IE6), AngularJS(IE9), EmberJS(IE8), WinJS(IE9) ),另有avalon.mobile,它可以更高效地运行于IE10等新版本浏览器中
  • 没有任何依赖,不到5000行,压缩后不到50KiB
  • 支持管道符风格的过滤函数,方便格式化输出
  • 局部刷新的颗粒度已细化到一个文本节点,特性节点
  • 要操作的节点,在第一次扫描就与视图刷新函数相绑定,并缓存起来,因此没有选择器出场的余地。
  • 让DOM操作的代码近乎绝迹
  • 使用类似CSS的重叠覆盖机制,让各个ViewModel分区交替地渲染页面
  • 节点移除时,智能卸载对应的视图刷新函数,节约内存
  • 操作数据即操作DOM,对ViewModel的操作都会同步到View与Model去
  • 自带AMD模块加载器,省得与其他加载器进行整合

学习教程

运行github中的示例

将项目下载到本地,里面有一个叫server.exe的.Net小型服务器(可以需要安装.Net4.0才能运行), 点击它然后打开里面与index开头的HTML文件,一边看运行效果,一边看源码进行学习。

JS文件的压缩

``` java -jar compiler.jar --js avalon.js --js_output_file avalon.min.js java -jar compiler.jar --js avalon.modern.js --js_output_file avalon.modern.min.js java -jar compiler.jar --js avalon.mobile.js --js_output_file avalon.mobile.min.js
<p>大家也可以在<a href="http://huati.weibo.com/k/avalon%E5%BF%AB%E6%8A%A5?from=501&order=time">新浪微博</a>第一时间了解它的变更或各种秘笈分享!</p>



```html
<!DOCTYPE html>
<html>
    <head>
        <title>avalon入门</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="avalon.js" ></script>
        <script>
            var first = 0;
            var model = avalon.define("test", function(vm) {
                vm.firstName = "司徒"
                vm.lastName = "正美"
                vm.fullName = {//一个包含set或get的对象会被当成PropertyDescriptor,
                    set: function(val) {//里面必须用this指向scope,不能使用scope
                        var array = (val || "").split(" ");
                        this.firstName = array[0] || "";
                        this.lastName = array[1] || "";
                    },
                    get: function() {
                        return this.firstName + " " + this.lastName;
                    }
                }
                vm.arr = ["aaa", 'bbb', "ccc", "ddd"]
                vm.selected = ["bbb", "ccc"]
                vm.checkAllbool = false
                vm.checkAll = function() {
                    if (!first) {
                        first++
                        return
                    }
                    if (this.checked) {
                        vm.selected = vm.arr
                    } else {
                        vm.selected.clear()
                    }
                }
                vm.checkOne = function() {
                    var bool = this.checked
                    if (!bool) {
                        vm.checkAllbool = false
                    } else {
                        vm.checkAllbool = vm.selected.size() === vm.arr.length
                    }
                }
            })

        </script> 
    </head>
    <body>
        <div ms-controller="test">
            <p>First name: <input ms-duplex="firstName" /></p>
            <p>Last name: <input ms-duplex="lastName"  /></p>
            <p>Hello,    <input ms-duplex="fullName"></p>
            <div>{{firstName +" | "+ lastName }}</div>
            <ul>
                <li><input type="checkbox" ms-duplex-radio="checkAllbool"  data-duplex-changed="checkAll"/>全选</li>
                <li ms-repeat="arr" ><input type="checkbox" ms-value="el" ms-duplex="selected" data-duplex-changed="checkOne"/>{{el}}</li>
            </ul>
        </div>

    </body>
</html>

源码内部的模块划分

从上至下,依次是

- 全局变量及方法 - avalon的静态成员定义区(主要是工具函数) - JavaScript 底层补丁 - DOM 底层补丁 - 配置系统 - 事件总线 - VM工厂(modelFactory) - 监控数组工厂(Collection) - 依赖调度系统(dispatcher) - 标签处理(parseHTML, innerHTML, clearHTML) - 扫描系统 - avalon的原型方法定义区(主要是DOM处理) - 指令定义区 - 编译系统 - 自带过滤器 - AMD加载器 - DOMReady

LOGO来历

http://tieba.baidu.com/p/1350048586

MVVM最先使用是在WPF,对于微软来说是从WinForm的MVP和其余的MVC衍生而来,
比MVP/MVC做到更多的就是数据的Binding,
是的数据的变化能即时以增量的形式反馈到View上。
同理的实现好像还有iOS delegate,为MVC提供类似binding的Publish/Subscribe功能