An elegant efficient express mvvm framework

Related tags

Frameworks avalon
Overview

npm version Travis CI Status Codecov LICENSE Build Status

Browser Matrix

npm install avalon2

es6调用方式

import * as avalon from 'avalon2'

English tutorials

avalon cookbook

这是基于官网制成的电子书,方便大家离线阅览

avalon2官网

这是基于gitbook制作的,对移动端支持很好,大家上班或睡觉时,可以过目一下.

avalon2+webpack2手脚架

QuickStart

大家期望已久的avalon2+mmRouter+各种组件的综合示例,不断完善中

UI库1

UI库2

avalon 单页后台管理系统框架:webpack+avalon+自定义avalon-router组件+jquery+bootstrap

avalon2 SPA脚手架 MS-BUS

一个 SPA 的脚手架(模块组织加载方式、单页面局部刷新技术、路由控制、后端数据的接入与模拟等实践/完整的增删改查示例)

avalon2 组件库 ANE

一个基于 bootstrap 的组件库,有用于数据展示的 table 组件、用于数据提交的 form 组件、用于消息提示的 message 与 notification 组件、dialog 组件和用户输入组件(input/textarea/checkbox/radio/select/datepicker/timepicker/upload)等,并且还在不断完善中


CDN: https://unpkg.com/[email protected]/dist/avalon.js

用法见https://unpkg.com/#/

请不要用2.0s这个最古老的版本

谁在用avalon

欢迎大家提交logo与官网链接

超高性能

测试页面 perf目录下的index.html, index1.4.html, index-ng.html, index-vue.html,index-react.html

亮点,如果页面上存在一个大表格或列表,其他框架会在浏览器加载页面时会卡一下(白屏), 而avalon则平缓多了

thanks http://charts.udpwork.com/

支持后端渲染

avalon2.1.5起支持后端渲染,详见这里

avalon2 学习教程(包括组件)

HTML指南

属性值必须用双引号括起,标签名必须小写, 标签必须被关闭(正常关闭,或自关闭)

组件, 在兼容IE6-8的情况下,组件必须用wbr, xmp做容器

组件名如果不充当标签名,可以不以ms-开头.

绑定属性建议使用短指令方式定义,即ms-if可以改成:if

ms-duplex指令除了change, rebounce过滤器外,不建议使用其他过滤器做格式化, 建议添加ms-input, ms-change在里面处理

ms-duplex不支持对简单数组的元素的处理, 即vm.arr = [1,2,4],

ms-important与ms-controller对应的vm.$id一个页面上只能用一次,不能存在多个同名的ms-controller. ms-important由于不继承上级的$element与$render,每次只更新它所在的区域,善用它能大大提高性能

   <div ms-controller='test'>{{@aaa}}div>
   <div ms-controller='test'>{{@bbb}}div>
   <div ms-important='test'>{{@bbb}}div>
Comments
  • avalon动画

    avalon动画

    avalon  动画指令, 是对现有JS动画库或CSS3动画的高级封装。avalon核心库本身不是提供任何动画功能。但凭借巧妙的设计,它能很好实现我们要的一切效果,甚至比jQuery实现的更简单更炫目!

    avalon 的动画指令 ms-effect="effectName",当effectName里面不包含{{}}时,属性值 就是我们要的特效名;否则,就会跑进内部的解析器,将{{}}里面的变量分析出来,与其他部分结合成我们要的特效名。

    这个特效名,其实是一组动画的名字,包括进入动画(entter),离开动画(leave)

    动画的实现可以通过CSS3或JS钩子函数 调用jQuery等库实现。

    如果你在动画开始时或结束后执行某些操作 ,那么,这就完成了。

     <script src="avalon.js"></script>
     <link rel="stylesheet" href="animate.css" type="text/css">
            <script>
                var vm = avalon.define({
                    $id: "test",
                    toggle: true,
                    click: function () {
                        vm.toggle = !vm.toggle
                    }
                })
            </script>
            <style>
                .aaa{
                    width:200px;
                    height: 40px;
                    background:#D2E0E6;
                }
            </style>
        <div ms-controller="test">
            <div class="aaa animated"  ms-effect='toggle'  ms-visible="toggle">xxxx</div>
            <button type="button" ms-click="click">btn</button>
      </div>
    

     有关动画的调用就是 ms-effect='toggle',与添加一个带动画效果的类名,它是来自animated.css库。

    如果需要回调,我们就需要用到avalon.effect方法来注册该特效要的回调或类名了。。。

    opened by RubyLouvre 26
  • 利用ms-include与监控数组实现一个树

    利用ms-include与监控数组实现一个树

    
    <!DOCTYPE html>
    <html>
        <head>
            <title></title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <script src="avalon.js"></script>
            <script>
                avalon.define("tree", function(vm) {
                    vm.tree = [
                        {text: "aaa", subtree: [
                                {text: 1111, subtree: []},
                                {text: 2222, subtree: [
                                        {text: 777, subtree: []}
                                    ]},
                                {text: 3333, subtree: [
                                        {text: 8888, subtree: []},
                                        {text: 999, subtree: []}
                                    ]}
                            ]},
                        {text: "bbb", subtree: [
                                {text: 4444, subtree: []},
                                {text: 5555, subtree: []},
                                {text: 6666, subtree: []}
                            ]},
                        {text: "ccc", subtree: []},
                        {text: "ddd", subtree: []},
                        {text: "eee", subtree: []},
                        {text: "fff", subtree: []}
                    ]
    
                })
            </script>
        </head>
        <body ms-controller="tree">
            <script type="avalon" id="tmpl">
                <ul ms-each-el="el.subtree">
                <li>{{el.text}}<div ms-include="'tmpl'" ms-visible="el.subtree.length" ></div></li>
                </ul>
            </script>
            <ul ms-each-el="tree">
                <li>{{el.text}}<div ms-include="'tmpl'" ms-visible="el.subtree.length" ></div></li>
            </ul>
        </body>
    </html>
    
    

    关键是如何递归调用自己

    opened by RubyLouvre 25
  • 关于 oniUI  tree组件的的问题

    关于 oniUI tree组件的的问题

    这是我的代码:

    define(['avalon', 'text!./departmentList.html'], function (avalon, tpl) { return function () { avalon.templateCache.departmentListTpl = tpl; var vm = avalon.define({ $id: "departmentListVM", tree:{}, $treeOpt:{}, det:{}, $skipArray:{}, items: [], dom:null, dept_parent:null, dept_name:null, dept_no:"", dept_id:"", moban:null, SuperiorName:"", add_dept_name:"", recommend:[], itemsDealing: [], itemsDealingCount: -1, // 代表未加载 itemsSuccess: [], itemsSuccessCount: -1, itemsFail: [], itemsFailCount: -1, curTabIndex: 0, // 处理状态 curStatus:0, loading:false,// 是否已加载完 $gridOpt:{ onInit: function(){ avalon.log("--init---") }}, pageable:false, autoResize: false, $pageSize:2, pageCount:10, $pageNo:1, $pageopt: { showJumper: true, showPages: 1, alwaysShowNext: true, perPages: 2, alwaysShowPrev: true, onJump: function (e, data) { vm.getItems(vm.curStatus); } }, child:[],

            // 加载itemList数据
            getItems: function (status) {
                // var pager = avalon.vmodels.taskPager;
                vm.loading=false;
                $.ajax({url:"../dePartment",
                    type:"post",
                    dataType: "json",
                   // data:{},
                    async : false,
                    success: function(data){
    
                        // var dataJSON = JSON.parse(data);
                        console.log("data:",data);
                        vm.child=data;
    
                        console.log('JSon:',vm.child.length);
                        vm.loading = true;
                    },
                    error:function(data,statusText){
                        console.log('出错了!!!!!!!!!',data.statusText);
                    }
                });
    
    
            },
            // 保存
            saveClick:function(){
                if (vm.det.$model.open){
                    vm.det.$model.open=1;
                }else{
                    vm.det.$model.open=0;
                }
                    vm.det.$model.dept_name=vm.dept_name;
                    vm.det.$model.dept_no=vm.dept_no;
    
                    console.log('进去了');
                    console.log('部门ID:',vm.dept_parent);
    
                    console.log('部门名称:',vm.dept_name);
                  vm.loading=true;
                  $.ajax({url:"../dePartment/update",
                    type:"post",
                    contentType: "application/json",
                    dataType: "json",
                     data:JSON.stringify(vm.det.$model),
                      async : false,
                      success: function(data){
                          vm.dom.context.innerText=vm.dept_name;
                          console.log('保存成功!',vm.dom.context.innerText);
                      },
                      error:function(data,statusText){
                        console.log('出错了!!!!!!!!!',data.statusText);
                      }
                  });
            },
            // 新建部门
            newClick:function(){
                vm.moban=1;
                if (vm.det.$model.open){
                    vm.det.$model.open=1;
                }else
                    {
                    vm.det.$model.open=0;
                    }
                /*for(var i=0;i<vm.child.length;i++){
                    if(vm.dept_parent==vm.child[i].dept_id){
                        console.log('父ID:',vm.child[i].dept_id,vm.child[i].dept_name);
                        vm.SuperiorName = vm.child[i].dept_name;
                        vm.dept_parent =  vm.child[i].dept_id;
                        break;
                    }
                }*/
                vm.SuperiorName= vm.dept_name;
                vm.det.$model.dept_parent = vm.dept_id;
    
                console.log('子ID:',vm.det.$model.dept_parent);
                console.log('名称:',vm.det.$model.dept_name);
    
    
            },  
            //保存新建
            addSaveClick:function(){
                vm.det.$model.dept_name = vm.add_dept_name;
                console.log('添加部门名称:',vm.det.$model.dept_name);
                $.ajax({url:"../dePartment/save",
                    type:"post",
                     contentType: "application/json",
                     dataType: "json",
                      data:JSON.stringify(vm.det.$model),
                       async : false,
                       success: function(data){
                           console.log('新建成功!');
                       },
                       error:function(data,statusText){
                        console.log('出错了!!!!!!!!!',data.statusText);
                       }
                   });
            },
            delClick:function(arg){
                console.log('元素:',arg);
                $.ajax({url:"../dePartment/del",
                    type:"post",
                     contentType: "application/json",
                     dataType: "json",
                      data:JSON.stringify(vm.det.$model),
                       async : false,
                       success: function(data){
                           $(vm.dom).remove();
                           console.log('删除成功!',data);
                       },
                       error:function(data,statusText){
                        console.log('出错了!!!!!!!!!',data.statusText);
                       }
                   });
            }
    
        });
        vm.tree = {
                children: vm.child,
                edit: {
                    showRemoveBtn: function(leaf) {
                        return leaf.level > 0
                    }
                },
                data: {     
                    simpleData: {
                         enable: true,
                         idKey: "dept_id",
                         pIdKey: "dept_parent"
                    },
                    key: {
                        name: "dept_name", 
                    },
                    keep: {
                        leaf: false,
                        parent: true
                    }
                },
                view: {
                    editNameSelectAll: true,
                    showLine: function(leaf) {
                        return true
                        return leaf.level > 1 || 1
                    }
                },
                callback: {
                    onExpand: function(leaf) {
                        console.log(leaf)
                    },
                    beforeRename: function(arg) {
                        console.log("before编辑")
                    },
                    onNodeCreated: function(arg) {
                        console.log("onNodeCreated")
                    },
                    onRename: function(arg) {
                        console.log("编辑")
                    },
                    beforeRemove: function(obj) {
                        return confirm("确认删除?")
                    },
                    beforeAdd: function(obj) {
                        return confirm("确认添加?")
                    },
                    beforeNodeCreated: function(arg) {
    
                         arg.newLeaf = {
                                 name: "管理员"
                             }
    
                        console.log('进来了:',arg);
                    },
                    onNodeCreated: function(arg) {
                        console.log("add")
                    },
                    onClick:function(arg){
                        vm.dom = $(this).parent().parent();
                        console.log('获取的元素:',vm.dom.context.innerText);
                        vm.moban = 0;
                        vm.det=arg.leaf.$model;
                        vm.dept_no = arg.leaf.$model.dept_no;
                        vm.dept_parent = arg.leaf.$model.dept_parent;
                        vm.dept_id = arg.leaf.$model.dept_id
                        vm.dept_name = arg.leaf.$model.dept_name;
                        console.log('部门ID:',arg.leaf.$model.dept_id);
                        console.log('部门名称:',arg.leaf.$model.dept_name);
                    }
                }
            }
            vm.$treeOpt = {
                children: vm.child
            }
            vm.$skipArray = ["tree"]
        avalon.vmodels.appVM.mainContent = "departmentListTpl";
    
    }
    avalon.scan()
    

    });

    child:[], 是绑定tree组件的数据的属性 getItem()是第一次加载数据的方法,也是我要从数据库里获取的数据赋值给child[] 但是呢,现在有一个问题出现了,当我第一次加载这个js的时候,我的tree组件并没有加载数据,这个tree组件没有获取到数据,当我调试以后我发现,加载当前js的时候,第一次并没有去执行getItem这个方法(我在man.js 控制这里处理了一下,当第一次加载“当前”的js时候,会去调用getItem这个方法)。 而是第一次去执行了这段代码: vm.tree = { children: vm.child, edit: { showRemoveBtn: function(leaf) { return leaf.level > 0 } },........(最后面这段代码)

    所以,现在有个问题,当我第二次加载当前js的时候,tree组件加载了数据,因为第二次调用这个js的时候会执行getItem方法。也就是说,第一次的时候vm.tree并没有得到数据。这该怎么去处理,虽然我知道了问题出在哪,也知道第一次应该给vm.tree数据,但是我并没有好的解决办法,对这个框架还不熟

    opened by z893495246 24
  • 组件里 onInit 会加载多次,以及其它BUG

    组件里 onInit 会加载多次,以及其它BUG

    avalon 版本:/*! built in 2016-6-7:11 version 2.07 by 司徒正美 */

    2016-06-08 23:14 更新

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title>确认订单</title>
        <link href="./main.css" rel="stylesheet">
        <script src="./avalon.js"></script>
    </head>
    <body>
    <div class="container" ms-controller="container">
        <div class="loading-wrap" ms-visible="@loadingWrapShow">数据加载中....</div>
        <xmp ms-widget="{is:'ms-container'}"></xmp>
    </div>
    <script>
    function heredoc(fn) {
        return fn.toString().replace(/^[^\/]+\/\*!?\s?/, '').
                replace(/\*\/[^\/]+$/, '').trim().replace(/>\s*</g, '><')
    }
    
    var container = heredoc(function() {
    /*
    <div>
      <xmp ms-widget="[{is:'ms-address-wrap', $id:'address'}]"></xmp>
    </div>
    
    */
    })
    
    
    // 主容器
    var vmContainer = avalon.define({
        $id: 'container',
        loadingWrapShow: true
    })
    
    avalon.component('ms-container', {
      template: container,
      defaults: {
      }
    })
    
    var addressTmpl = heredoc(function() {
    /*
    <div class="address-wrap ms-controller" ms-visible="@addressWrapShow">
        <div class="wrap-header">
            <h3>选择收货地址</h3>
            <span class="small-text">美的商城配送方式:快递(免运费)</span>
            <a class="right-text" href="javascript:;" ms-click="@addressListExpand = !@addressListExpand" ms-visible="@addressTotal > 3">
                <span ms-visible="!@addressListExpand">展开</span><span ms-visible="@addressListExpand">收起</span>更多收货地址<i class="icon_arrow_bottom" ms-class="{icon_arrow_top: @addressListExpand}"></i></a>
        </div>
        <div class="address-box">
            <!--ms-for:(index, el) in @addressList-->
            <div class="adr"
                 ms-class="{'default': (el.nIsDefault == 1 ? (@checkDefault(el) && true) : false), 'checked': (@addressChecked.lAddrId == el.lAddrId), hide: (index > 2 && ! @addressListExpand)}"
                 ms-hover="'hover'"
                 ms-click="@addressChecked = el">
                <div class="adr-inner" ms-attr="{title: (el.strProvince + el.strCity + ' ' + el.strPersonName)}">
                    <i class="icon_checked"></i>
                    <div class="adr-head" >
                        <span class="adr-province" ms-text="el.strProvince"></span>
                        <span class="adr-city" ms-text="el.strCity"></span>
                        <span class="adr-name" ms-text="el.strPersonName"></span>
                    </div>
                    <div class="adr-body" ms-attr="{title: (el.strArea + el.strDetailMsg + ' ' + el.strMobileNum)}">
                        <p class="adr-text">
                            <span class="adr-county" ms-text="el.strArea"></span>
                            <span class="adr-detail" ms-text="el.strDetailMsg"></span>
                            <span class="adr-tel" ms-text="el.strMobileNum"></span>
                            <span class="adr-default-text">[默认]</span>
                        </p>
                    </div>
                    <div class="adr-foot">
                        <a href="javascript:;" ms-click="@editAdrress(el, $event) | stop">编辑</a>
                        <a href="javascript:;" ms-click="@deleteAddress(el, $event) | stop">删除</a>
                    </div>
                </div>
            </div>
            <!--ms-for-end:-->
    
            <div class="adr" ms-hover="'hover'" ms-click="@editAdrress({}, $event)">
                <div class="adr-inner">
                    <div class="adr-add">
                        <p class="adr-add-icon"><i class="icon_add"></i></p>
                        <p class="adr-add-text">添加地址</p>
                    </div>
                </div>
            </div>
        </div>
        <xmp ms-widget="[{is:'mdui-dialog', $id:'addressDeleteDialog'}, @dialogAddressDeleteConf]">
    
        </xmp>
        <xmp ms-widget="[{is:'mdui-dialog', $id:'addressEditDialog'}, @dialogAddressEditConf]">
            <div slot="body">
    
                <div class="btn-box">
                    <div class="addr-btn blue" ms-click="@confirmDialog | stop">保存</div>
                    <div class="addr-btn" ms-click="@closeDialog | stop">取消</div>
                </div>
            </div>
            <div slot="foot"></div>
        </xmp>
    </div>
    */
    })
    
    avalon.component('ms-address-wrap', {
        template: addressTmpl,
        defaults: {
            addressChecked: {},
            addressDelete: {},
            defaultAddressEdit: {
                lAddrId: '',
                strArea: '',
                strAreaCode: '',
                strCity: '',
                strCityCode: '',
                strDetailMsg: '',
                strMobileNum: '',
                strPersonName: '',
                strProvince: '',
                strProvinceCode: ''
            },
            addressEdit: {},
            addressListExpand: false,
            addressList: [],
            addressTotal: 0,
            addressWrapShow: false,
            dialogAddressDeleteConf: {
                dialogType: 'confirm', // confirm info tips
                dialogIcon: 'info',
                dialogShow: false,
                onConfirm: function(e) {
                    avalon.log('AddressDelete confirm')
                },
                onClose: function() {
                    avalon.log('AddressDelete close')
                }
            },
            dialogAddressEditConf: {
                dialogType: 'confirm', // confirm info tips
                dialogIcon: false,
                dialogWrapCss: {width: 800},
                dialogShow: false,
                onConfirm: function(e) {
                    avalon.log('AddressEdit confirm')
                },
                onClose: function() {
                    avalon.log('AddressEdit close')
                }
            },
            // 选中默认地址
            checkDefault: function (addr) {
                if (! this.addressChecked.lAddrId) {
                    this.addressChecked = addr
                }
            },
            // 获取地址列表数据
            getAll: function() {
                this.addressList = [{"lAddrId":10677,"lUin":12070,"strPersonName":"\u6ee8\u6cb31","strMobileNum":"11111111111","strProvince":"\u5e7f\u4e1c\u7701","strProvinceCode":"440000","strCity":"\u6df1\u5733\u5e02","strCityCode":"440300","strArea":"\u798f\u7530\u533a","strAreaCode":"440304","strDetailMsg":"\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3\u6ee8\u6cb3","nIsDefault":1},{"lAddrId":10724,"lUin":12070,"strPersonName":"\u8fdb\u57ce\u4e0d3\u70c33\u4e2d\u5730\u7c89\u5730","strMobileNum":"11111111111","strProvince":"\u6cb3\u5317\u7701","strProvinceCode":"130000","strCity":"\u77f3\u5bb6\u5e84\u5e02","strCityCode":"130100","strArea":"\u957f\u5b89\u533a","strAreaCode":"130102","strDetailMsg":"12321321313213","nIsDefault":null},{"lAddrId":10725,"lUin":12070,"strPersonName":"\u9648\u6d69","strMobileNum":"18611111111","strProvince":"\u5317\u4eac\u5e02","strProvinceCode":"110000","strCity":"\u5317\u4eac\u5e02","strCityCode":"110100","strArea":"\u4e1c\u57ce\u533a","strAreaCode":"110101","strDetailMsg":"\u5b66\u5e9c\u8def\u6021\u5316\u91d1\u878d\u79d1\u6280\u5927\u53a623\u697c","nIsDefault":null},{"lAddrId":10726,"lUin":12070,"strPersonName":"\u6d82\u6d82","strMobileNum":"18611111111","strProvince":"\u5c71\u897f\u7701","strProvinceCode":"140000","strCity":"\u5927\u540c\u5e02","strCityCode":"140200","strArea":"\u5357\u90ca\u533a","strAreaCode":"140211","strDetailMsg":"\u7389\u5f8b\u8def\u82b1\u6837\u5e74\u82b1\u4e61A\u680b9O","nIsDefault":null},{"lAddrId":10727,"lUin":12070,"strPersonName":"\u840c\u840c","strMobileNum":"18611111111","strProvince":"\u6cb3\u5317\u7701","strProvinceCode":"130000","strCity":"\u5510\u5c71\u5e02","strCityCode":"130200","strArea":"\u8def\u5357\u533a","strAreaCode":"130202","strDetailMsg":"\u6d77\u79c0\u8def21\u53f7\u9f99\u5149\u4e16\u7eaa\u5927\u53a6B\u5ea711\u697c","nIsDefault":null}];
                this.addressTotal = this.addressList.length
                this.addressWrapShow = true
                this.loadingWrapShow = false
            },
            // 弹出确认删除浮层
            deleteAddress: function(addr, e) {
                this.addressDelete = addr
                this.dialogAddressDeleteConf.dialogShow = ! this.dialogAddressDeleteConf.dialogShow
            },
            // 弹出地址编辑浮层
            editAdrress: function(addr, e) {
                var self = this
                self.dialogAddressEditConf.dialogShow = ! self.dialogAddressEditConf.dialogShow
            },
            onInit: function() {
                var self = this
                setTimeout(function() {
                    self.getAll.call(self)
                }, 3000)
    
                this.addressEdit = avalon.mix({}, this.defaultAddressEdit)
                avalon.log('onInit 会加载多次')
            }
        }
    })
    
    
    var dialogTmpl = heredoc(function() {
    /*
    <div>
      <div class="mdui-dialog-mask" ms-visible="@dialogShow" ms-if="@dialogMask"></div>
      <div class="mdui-dialog"
        ms-css="@dialogWrapCss"
        ms-class="['mdui-dialog-' + @dialogType, @dialogWrapClass]"
        ms-visible="@dialogShow">
        <a class="mdui-dialog-close" href="javascript:;"
            ms-click="@closeDialog"
            ms-if="@dialogType != 'tips' && @dialogCloseXShow">&times;</a>
        <i ms-class="['mdui-dialog-icon-' + @dialogIcon]" ms-if="@dialogIcon"></i>
        <div class="mdui-dialog-confirm-content" ms-if="@dialogType != 'tips'">
            <div class="mdui-dialog-head" ms-visible="@dialogHeadShow">
              <slot name="head"></slot>
            </div>
            <div class="mdui-dialog-body" ms-visible="@dialogBodyShow">
                <slot name="body"></slot>
            </div>
            <div class="mdui-dialog-foot mdui-dialog-btns-inline"
                ms-class="['mdui-dialog-btns-inline' + @dialogFootBtnNum]"
                ms-visible="@dialogFootShow">
                <slot name="foot">
                    <a class="mdui-dialog-btn" href="javascript:void(0)" ms-click="@confirmDialog">确 认</a>
                    <a class="mdui-dialog-btn" href="javascript:void(0)" ms-click="@closeDialog">取 消</a>
                </slot>
            </div>
        </div>
        <div class="mdui-dialog-tips-content" ms-if="@dialogType == 'tips'">
            <slot name="content">正在加载中,请稍候......</slot>
        </div>
      </div>
    </div>
    */
    })
    
    // 组件定义
    avalon.component('mdui-dialog', {
      template: dialogTmpl,
      defaults: {
        dialogType: 'confirm', // confirm info tips
        dialogIcon: 'info', // info  success
        dialogWrapClass: '', // 指定额外的 dialog 容器 class
        dialogWrapCss: {}, // // 指定额外的 dialog 容器 css
        dialogShow: false,
        dialogCloseXShow: true,
        dialogHeadShow: true,
        dialogBodyShow: true,
        dialogFootShow: true,
        dialogMask: true,
        dialogFootBtnNum: 0, // 底部按钮个数
        confirmDialog: function(e) {
            var result = this.onConfirm(e, this)
    
            if (result !== false) {
                this.dialogShow = ! this.dialogShow
            }
        },
        closeDialog: function(e) {
            this.onClose(e, this)
            this.dialogShow = ! this.dialogShow
        },
        onConfirm: avalon.noop,
        onShow: avalon.noop,
        onClose: avalon.noop,
    
        onInit: function(e) {
        },
        onReady: function(e) {
            //this.dialogFootBtnNum = $(e.target).find('.mdui-dialog-foot a').length
            this.onShow(e, this)
        },
        onViewChange: function(e) {
            // var $dialog =  $(e.target).find('.mdui-dialog')
            // var top = - Math.floor($dialog.height() / 2) - 100
            // var left = - Math.floor($dialog.width() / 2)
            // $dialog.css({'margin-top': top, 'margin-left': left})
        }
      }
    })
    
    </script>
    </body>
    </html>
    
    
    
    opened by visamz 23
  • vm更新时, 即使某些model没变化, 其对应的view也增加了新的元素

    vm更新时, 即使某些model没变化, 其对应的view也增加了新的元素

    虽然table绑定的model (testRange) 并未改变. 但每点一次按钮, 下面的表格就会增加若干行若干列.

    <!DOCTYPE html>
    <html>
        <head>
            <title>first example</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">        
    
             <script src="avalon.js"></script>
    
        </head>
        <body>
    
      <script>  
    
    
    var data1 = [{"Id":-10,"Name":"管理","ParentId":1},{"Id":-8,"Name":"工具","ParentId":1},{"Id":3,"Name":"用户管理","ParentId":-10},{"Id":5,"Name":"角色管理","ParentId":-10},{"Id":15,"Name":"公告管理","ParentId":-10},{"Id":18,"Name":"日志管理","ParentId":-10},{"Id":17,"Name":"个人资料","ParentId":-10},{"Id":96,"Name":"页面访问统计","ParentId":-10},{"Id":109,"Name":"菜单汇总","ParentId":-10},{"Id":4,"Name":"菜单管理","ParentId":-8},{"Id":65,"Name":"航空公司管理","ParentId":-8},{"Id":66,"Name":"分公司管理","ParentId":-8},{"Id":32,"Name":"数据生成","ParentId":-8},{"Id":104,"Name":"预测精度报表数据生成","ParentId":-8}];
    
    var data2 = [{"Id":-8,"Name":"工具","ParentId":1},{"Id":3,"Name":"用户管理","ParentId":-10},{"Id":5,"Name":"角色管理","ParentId":-10},{"Id":15,"Name":"公告管理","ParentId":-10},{"Id":18,"Name":"日志管理","ParentId":-10},{"Id":17,"Name":"个人资料","ParentId":-10},{"Id":96,"Name":"页面访问统计","ParentId":-10},{"Id":109,"Name":"菜单汇总","ParentId":-10},{"Id":4,"Name":"菜单管理","ParentId":-8},{"Id":65,"Name":"航空公司管理","ParentId":-8},{"Id":66,"Name":"分公司管理","ParentId":-8},{"Id":32,"Name":"数据生成","ParentId":-8},{"Id":104,"Name":"预测精度报表数据生成","ParentId":-8}];
    
    
    
        window.vm = avalon.define({
            $id: "start2",
            data: avalon.mix(true, [], data1), //复制一个副本给vm, 不然后面修改vm.data的时候,会破坏data1的原始数据. 不利于后面的切换演示. 这里的参数true表示是深拷贝
    
            testRange:avalon.range(10),
            isData2:false,
            change:function(){
                if(this.isData2){
                    this.data=[];//修改data前, 先清空. 不然最终结果会被原来的数据污染. 注意, 数据源只能为[],{}, 不能为null.
                    this.data=avalon.mix(true, [], data1);
                    this.isData2=false;
                }
                else{
                    this.data=[]; 
                    this.data=avalon.mix(true, [], data2);
                    this.isData2=true;
                }
            },
            onCellClick: function(rowIndex,colIndex,ev){
                console.log("onCellClick "+rowIndex+" "+colIndex);
            },
            onTHClick: function(colIndex,ev){
                console.log("onTHClick "+colIndex);
            }
        }) 
    
    
    
        </script>
    
        <div ms-controller="start2"> 
           <button type=button ms-click="##change()">Change</button>
           <div ms-for="(index,el) in ##data" ms-if="el.Id<0" style="display:inline-block; border:solid 1px gray; padding:10px;vertical-align:top">
                 <div style='font-weight:bold'>
                 --{{index}}--{{el.Id}}--{{el.Name}}
                 </div>
                 <div ms-for="(index2,el2) in ##data" ms-if="el2.ParentId==el.Id">
                 --{{index2}}--{{el2.Id}}--{{el2.Name}}             
                </div>             
          </div> 
    
          <table>
              <tr >
              <th style="border:solid 1px gray" ms-for="(colIndex,el2) in ##testRange" ms-click="@onTHClick(colIndex,$event)" >
                      {{el2}}
                </th>
              </tr>
            <tr ms-for="(rowIndex,el) in ##testRange" >
                  <td style="border:solid 1px gray" ms-for="(colIndex,el2) in ##testRange" ms-click="@onCellClick(rowIndex,colIndex,$event)" >
                      {{el*el2}}
                </td>
            </tr>
          </table>
    
        </div> 
    
        </body>
    </html>  
    
    opened by alanthinker 23
  • 通过JS修改属性时触发DOM回调

    通过JS修改属性时触发DOM回调

    <!DOCTYPE html>
    <html lang="en">  
        <head>  
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>司徒正美 通过JS修改属性时触发DOM回调</title>    
            <script>
                window.onload = function() {
                    //支持IE11,chrome,firefox(IE6-8使用onpropertychange, IE9开始由于弱化了onpropertychange,需要用轮询),新出的MutationObserver帮不上忙
                    //修改Element.prototype, HTMLElement.prototype,HTMLInputElement.prototype都无效,必须直接修改元素实例
                    //可能这只能对不存在的属性,想修改固有属性只能在实例上操作
                    //http://www.cnblogs.com/rubylouvre/archive/2012/05/28/2520721.html
                    aaa.__defineSetter__("value", function(newValue) {
                        var node = this.attributes.value
                        if (!node || newValue !== node.value) {
                            var event = document.createEvent("Event")
                            event.initEvent("input", true, true)
                            this.setAttribute("value", newValue)
                            if (document.documentElement.contains(this)) {
                                this.dispatchEvent(event)
                            }
                        }
                    })
                    aaa.__defineGetter__("value", function() {
                        var node = this.attributes.value
                        return node ? node.value : ""
                    })
                    setTimeout(function() {
                        aaa.value = "值改变了"
                    }, 3000)
    
                }
            </script>
        </head>  
        <body>  
            <input id=aaa oninput="alert(this.value)" value="aaa" >
        </body>  
    </html> 
    
    功能增强 
    opened by RubyLouvre 23
  • 最新版本bug

    最新版本bug

    • built in 2016-7-6:3 version 2.10 by 司徒正美 更新到最新版本后 出现了以下报错 在2f16f41这个版本上没问题 html TypeError: Cannot set property 'textContent' of undefined(…) TypeError: Cannot set property 'textContent' of undefined at Function.avalon.clearHTML (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:2558:23) at avalon.directive.update (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:3705:17) at module.exports (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:3362:10) at Object.avalon.directive.diff (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:3697:14) at http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:7441:39 at RegExp.Symbol.replace at String.replace (native) at diffProps (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:7436:19) at diff (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:7404:22) at diff (http://127.0.0.1:8020/systems/vendor/avalon/avalon.js:7407:22) diffProps error
    <body>
            <div ms-controller="test">
                <div ms-html="@tpl"></div>
                <button ms-click="@switch1">切换1</button>
                <button ms-click="@switch2">切换2</button>
            </div>
            <script>
                require.config({ //依赖配置
                    paths: {
                        text: 'vendor/require/text.min',
                        avalon: 'vendor/avalon/avalon'
                    }
                });
    
                require(['avalon'], function(avalon) {
                    var vm = avalon.define({
                        $id: 'test',
                        tpl: "",
                        switch1: function() {
                            require(['1.js'], function(module) {
                                module.load();
                            });
                        },
                        switch2: function() {
                            require(['2.js'], function(module) {
                                module.load();
                            });
                        }
                    });
    
                    avalon.component('ms-span', {
                        template: "<span>123</span>",
                        defaults: {
                        }
                    });
                });
            </script>
        </body>
    

    1.js

    define(['avalon', 'text!./123.html'], function(avalon, tpl) {
        var vm = avalon.define({
            $id: 'test2'
        });
    
        return {
            load: function() {
                avalon.vmodels.test.tpl = tpl;
            }
        }
    });
    

    123.html

    <div ms-controller="test2">
        <xmp ms-widget="{is:'ms-span'}"></xmp>
    </div>
    

    2.js

    define(['avalon', 'text!./456.html'], function(avalon, tpl) {
        var vm3 = avalon.define({
            $id: 'test3'
        });
    
        return {
            load: function() {
                avalon.vmodels.test.tpl = tpl;
            }
        }
    });
    

    456.html

    <div ms-controller="test3">
    <xmp ms-widget="{is:'ms-span'}"></xmp>
    </div>
    
    opened by shanzhongke 22
  • avalon.mobile.js的几个问题

    avalon.mobile.js的几个问题

    其实是ms-on-tap ms-on-hold的问题。 1.元素绑定tap事件后,无论长按多久,只要手指不移动释放手指就会触发tap事件,正确的是只要长按超过一定时间(clickDuration),释放手指都不会触发tap事件; 2.元素绑定tap事件后,手指按住元素,然后移动,超过dragDistance,释放手指,发现元素上的ms-active-class还存在,不是应该去掉吗? 3.当一个元素同时绑定了tap和hold事件后,长按元素超过一定时间(clickDuration),然后释放手指,发现会同时触发tap和hold事件。。。。 4.传统的hold事件不是长按元素超过一定时间后就会触发的吗(无论你有木有释放手指)?avalon的是你必须释放手指才会触发。。。。。

    opened by weeksun23 22
  • @司徒大哥。  tree组件添加,删除按钮失效

    @司徒大哥。 tree组件添加,删除按钮失效

    总是报错:Uncaught TypeError: arr.pushArray is not a function 我的代码是按照UI的列子copy过来改了一下。事件代码那一块没有动。

    @RubyLouvre 大哥帮我看看呗,刚接触这个框架

      vm.tree = {
                    children: vm.zNodes,
                    edit: {
                        showRemoveBtn: function(leaf) {
                            return leaf.level > 0
                        }
                    },
                    data: {
                        simpleData: {
                             enable: true,
                             idKey: "dept_id",
                             pIdKey: "dept_parent"
                        },
                        key: {
                            name: "dept_name", 
                        },
                        keep: {
                            leaf: false,
                            parent: true
                        }
                    },
                    view: {
                        editNameSelectAll: true,
                        showLine: function(leaf) {
                            return true
                            return leaf.level > 1 || 1
                        }
                    },
                    callback: {
                        onExpand: function(leaf) {
                            console.log(leaf)
                        },
                        beforeRemove: function(obj) {
                            return confirm("确认删除?")
                        },
                        onRemove: function(leaf) {
                            console.log("remove " + leaf)
                        },
                        onRename: function(arg) {
                            console.log("renamed")
                        },
                        beforeAdd: function(obj) {
                            return confirm("确认添加?")
                        },
                        onNodeCreated: function(obj) {
                            avalon.log("node onNodeCreated")
                        }
    
    
                    }
    
                }
                vm.$treeOpt = {
                    children: [vm.child[0]]
                }
                vm.$skipArray = ["tree"]
    
    opened by z893495246 20
  • checkbox的ms-duplex-checked的问题

    checkbox的ms-duplex-checked的问题

    已更新到最新版本,问题:点击change按钮,checked值改变后div的class未连动,昨天下午4点前的版本没有这个问题 代码如下

    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <script type="text/javascript" src="/vendor/plug-in/avalon2/avalon.js"></script>
        <script type="text/javascript" src="/vendor/plug-in/jquery/jquery.js"></script>
        <style>
            .red {
                color:red;
            }
        </style>
    </head>
    <body>
    <div ms-controller="tree">
        <div ms-class="{red:@red}">哈哈哈</div>
        <input id="cb1" type="checkbox" ms-duplex-checked="@red"/>
        <input type="button" value="change" ms-click="@change"/>
    </div>
    </body>
    <script>
    
        avalon.define({
            $id: "tree",
            red: false,
            change: function() {
                var cb = document.getElementById('cb1');
                cb.checked = !cb.checked;
            }
        });
    </script>
    </html>
    
    
    opened by gogtz 19
  • bootstrap的css与avalon的冲突,导致ms-text不能即时渲染出来

    bootstrap的css与avalon的冲突,导致ms-text不能即时渲染出来

    • built in 2016-8-30:17 version 2.114 by 司徒正美
    • npm 2.1.14
    • IE 8(测的浏览器不多,chrome跟firefox都没问题)

    依然是“发送完验证码后需要等待一段时间才能重新发送”的场景。 问题描述:使用了bootstrap的css,在disabled的

    opened by Array-Huang 18
  • R.I.P

    R.I.P

  • 1.4.4(Jun 17, 2015)

    • 更新随机数的生成策略
    • 内部方法registerSubscriber更名为avalon.injectBinding并暴露出来
    • 重构ms-repeat,ms-with,ms-each,监控数组都共享一个代理VM, data.element在初始化变成一个注释节点,方便以后rollback不再进行收集回调这些重复操作
    • 重构scanAttr,减少不必要的操作
    • 重构modelFactory
    • 重构modelFactory.shim, 将VB实现的hash改成JS实现的hash,并且没有了 VBClassBodies=CreateObject(\"Scripting.Dictionary\") 再也不担心IE安全级别警告了
    • FIX scanAttr模块中对绑定对象的priority值的兼容问题
    • 重构GC 垃圾回收
    • 统一为所有绑定对象添加uuid, lists属性,去掉vars属性
    • 优化 truncate过滤器
    • fix 1.4.2中对html绑定的修改造成的 BUG,当用户数据为数字布尔时就会出错
    • fix removeAll传入数组时, 只能除第一个匹配元素的BUG
    • fix bindingExecutors["if"]的 value为false, node为注释节点时,会被多次执行而抛错的BUG
    • fix $compute在IE6-8引发对象不支持此属性或方法的BUG
    Source code(tar.gz)
    Source code(zip)
  • 1.4.3(May 14, 2015)

    修复【ms-attr绑定对布尔属性的值为false】的BUG,必须先设置为false,再用removeAttribute移除 修复【avalon.modern下data()方法】 BUG 修复【postion()对父元素出现滚动条取值不正确】的BUG 修复【ms-include-src在循环绑定中发出N多相同请求】的BUG 修复avalon移动端无法触发select下拉选框bug 修复【require方法在IE6-8下的】BUG 修复【toggleClass】 BUG 第一个参数必须为字符串 修复ms-repeat在添加或删除项时会导致其他项重新渲染的BUG 修复【为监控数组删除或添加项时会让触发其它项更新】的BUG, 修复方法为$index, $first, $last, el不再共享订阅 数组,el进行依赖收集时是通过$index实现的,在收集前,将$index的订阅数组改为el的 #817 修复【vml元素变成不可以访问元素】的BUG——scanAttr不能对VML元素访问nodeType属性;IE6-8下如果访问VML元素的type属性,就让会它的所有属性值都变成,这时我们再访问它的这些属性时,就会抛错

    重构ms-duplex在SELECT元素上的实现,原来是通过不稳定的checkScan判定其子孙节点被扫描完毕才设置selected属性,现在是通过更可靠的duplexCallback回调实现

    强制触发 widget 的$init方法

    重构html绑定

    Source code(tar.gz)
    Source code(zip)
  • 1.4.2(Apr 15, 2015)

    修正parseHTML 对非标签类型的字符串解析失败的BUG 修正监控数组push方法没有同步$last属性的BUG 更改safari5.x下contains方法的存在性检测 更改对avalon.*.shim文件的构建 修正IE6-11下的ms-duplex-checked BUG 优化提示信息 添加data-include-cache辅助指令 修正自带加载器package配置项的BUG 修正avalon.modern中data-duplex-observe的BUG 修正IE全系列下使用ms-attr操作布尔属性时, 当表达式为false时,没有像其他现代浏览器那样移除该属性,而是只置为空字符,导致CSS出问题的BUG

    Source code(tar.gz)
    Source code(zip)
  • 0.9.9(Apr 15, 2015)

    • 修正 updateViewModel bug
    • 修正监控数组的set方法 bug
    • 添加data-each-rendered, data-repeat-rendered, data-with-rendered, data-include-loaded, data-include-rendered等回调
    • 支持使用noscript标签做模板
    • 升级select 元素的ms-duplex绑定
    • update ms-repeat的clear分支
    • fix gatherRemovedNodes bug
    • 修复ms-active在按住鼠标的情况下移除element不能移除类名的bug
    • 升级触屏模块
    • 升级扫描机制,解决ms-if BUG
    • AMD加载器支持requirejs风格的paths, shim配置项
    • 对parseExpr进行改进,引入了缓存机制,重复利用已有的求值函数。这对使用ms-each, ms-repeat循环生成表格或下拉框非常有帮助,它可以支持到2000左右的大数组了。
    • 修复重新赋值vm后,filters丢失的问题
    • 移除ms-bind, ms-ui绑定
    Source code(tar.gz)
    Source code(zip)
  • 0.9.7(Apr 15, 2015)

    • fix 带参数的事件回调不能阻止默认行为的BUG 这里内部
    • fix ms-if对应的节点有样式时,会出现闪屏的现象 这里
    • 对ms-data进行增强,允许直接绑定一个对象,使用 el["data-xxx"]来取得这对象
    • chrome使用removeAttributeNode移除不存在的特性节点时会报错
    • 对ms-class的新风格进行强化,在添加新类名时移除旧类名
    • 处理IE6-8下,html过滤器引发的导常
    • 将avalon.cssNumber暴露出来
    • 处理IE9下input事件的模拟,谢谢一群的长风,荣誉,5群的蚂蚁等人帮忙测试
    • FIX对移出DOM的父节点进行插入孩子操作时抛异常的BUG ,这个与上面的removeAttributeNode的问题相仿,不过上面的解决方案是使用removeAttribute搞定,估计removeAttribute 内部是自带hasAttribute判定,能吞掉这异常。
    Source code(tar.gz)
    Source code(zip)
  • 0.7.3(Apr 15, 2015)

  • 0.7.2(Apr 15, 2015)

    本版本修正@月王提出的关于visible的BUG,比如说用户是用DIV摸拟的按扭,会将它的display改成inline-block,之前avlaon只是简单地取它的默认值,得到block,因此隐藏再显示后,按钮就会占满一行,让用户布局崩溃了。

    此外,从本版本开始,avalon将从mass中分家,有自己独立的仓库,地址为https://github.com/RubyLouvre/avalon

    Source code(tar.gz)
    Source code(zip)
  • 1.4.1(Mar 18, 2015)

    重构parseHTML,让其支持xhtml https://github.com/RubyLouvre/avalon/commit/1cfbd3cf9163c5dd8d48315a0e2a60d2961202e2 强化 ms-duplex-number拦截器 添加data-duplex-number辅助指令 值为strong medium weak https://github.com/RubyLouvre/avalon/commit/188941a36dff3a73341db3422bc46387655918be ms-duplex添加对input[type=hidden]的支持 https://github.com/RubyLouvre/avalon/commit/ad6c96a97bbe57c3e88452428a2927882d1dbc5f createCache改为LRU实现,avalon.nextTick大重构 https://github.com/RubyLouvre/avalon/commit/7f75e32309c319ca53c9f82c5f5bc0d51ab7beb1 fix avalon.ready触发两次的BUG https://github.com/RubyLouvre/avalon/commit/90eebdf7f279180d1b9036348c8486cc7bfff890 fix getToken BUG,https://github.com/RubyLouvre/avalon/commit/439511cfbd7f0e4da78bc9a158143da8aa2ca589 number过滤器回到支持三个参数的情况 https://github.com/RubyLouvre/avalon/commit/9354edddc3a961a09f03536809e7d7ba2b1db125

    Source code(tar.gz)
    Source code(zip)
  • 1.4.0(Feb 15, 2015)

    avalon1.4.0发布,三个重大改进。1 全新的兼容AMD规范requirejs API的加载器; 2 使用gulp进行构建; 3 兼容性更好的触屏模块

    Source code(tar.gz)
    Source code(zip)
  • 1.3.9.1(Jan 27, 2015)

  • 1.3.9(Jan 27, 2015)

    • ms-html内部不再使用异步
    • head元素中的avalon元素加入ms-skip指令
    • 重构计算属性,现在超级轻量化
    • 重构CG回收,不会每次都全部检测所有绑定对象
    • 重构内部方法isArrayLike,更好的判定非负整数
    • 重构number过滤器
    • 重构widget的节点回收,去掉onTree方法
    • 重构Collection内部工厂
    • 重构modelFactory, 现在VM.$event.$digest开启异步刷新视图功能
    • 重构offsetParent
    • 重构ms-repeat,不再触发多余的回调
    • 针对IE下 MutationObserver 会撕碎文本节点BUG, 添加 mergeTextNode 内部方法
    • 优化短路与, 短路或的处理逻辑
    • 支持CommonJS和AMD和单文件三种方式引用,支持通过bower命令加载avalon
    • avalon.modern.js遗漏了 parseJSON补上,并且修正parseJSON的逻辑与原生的JSON.parse保持一致
    • 去掉所有与scanCallback相关的定时器

    本次升级带来的最大的特性是$digest

    在之前的版本,如果我们对VM的某个监控属性连续地改动,每次改动都立即同步到视图,并触发对应的$watch回调。

    <!DOCTYPE html>
    <html>
        <head>
            <title>TODO supply a title</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width">
            <script src="avalon.js"></script>
            <script>
                var vm = avalon.define({
                    $id: "test",
                    aaa: 111
                })
                vm.$watch("aaa", function(v) {
                    console.log(v)
                })
    
                vm.aaa = 1
                vm.aaa = 2
                vm.aaa = 3
    
            </script>
        </head>
        <body ms-controller="test">
            {{aaa}}
        </body>
    </html>
    

    控制台会依次输出1,2,3

    <!DOCTYPE html>
    <html>
        <head>
            <title>TODO supply a title</title>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width">
            <script src="avalon.js"></script>
            <script>
                var vm = avalon.define({
                    $id: "test",
                    aaa: 111
                })
                vm.$events.$digest = true
                vm.$watch("aaa", function(v) {
                    console.log(v)
                })
    
                vm.aaa = 1
                vm.aaa = 2
                vm.aaa = 3
    
            </script>
        </head>
        <body ms-controller="test">
            {{aaa}}
        </body>
    </html>
    

    这时只输出一次,这对于一些类似于mousemove的频繁操作非常有利,大大提升性能。

    最近一朋友用avalon做的一个使用avalon的模板项目。https://github.com/pinghe/seedfrontend

    此原型项目展示了:

    • 支持cordova、browser应用,即同一套代码可用于桌面浏览器和各类手机应用。
    • 使用avalon MVVM框架
    • 使用cordova 用于移动端
    • 使用requirejs amd模块加载器
    • 使用gulp构建系统
    • 展示了页面切分和逻辑模块划分(html、css、js),及如何根据实际切换模块。适用团队分工合作
    • 页面路由技术,页面转换的有限状态机应用。
    • 支持js、coffee脚本
    • 支持css、less、sass 文件
    • 支持三种应用场景,浏览器,移动app
    • 支持生产环境,即可将js合并压缩成单个js文件,优化css文件,优化html文件
    • 支持DevOps

    这是另一个朋友用avalon搭建后台系统的心得,《使用mvvm框架avalon开发公司内部运营管理系统的一些心得》

    Source code(tar.gz)
    Source code(zip)
  • 1.3.8.1(Jan 27, 2015)

    1.3.8的急紧修复版

    • 让ms-text, ms-html支持过滤器,方便在首屏渲染时不出现插值表达式
    • fix ms-html延迟扫描的BUG
    • 重构modelFactory
    Source code(tar.gz)
    Source code(zip)
  • 1.3.8(Jan 27, 2015)

    avalon1.3.8主要是在ms-repeat、 ms-each、 ms-with等循环绑定上做重大性能优化,其次是对一些绑定了事件的指令添加了roolback,让其CG回收更顺畅。

    • 重构ms-repeat、ms-each、ms-with, 内部的代理对象全部使用普通的对象实现, 并且一个监控数组只对应一个代理VM数组,从而大量减少VM的数量。
    • avalon不再使用scanCallback实现内部各种rendred回调,改成checkScan方法。详看这里的例子
    • fix parseHTML在旧式IE下动态生成tr元素,多添加了caption元素的BUG
    • getEachProxy方法在ms-repeat, ms-duplex混合使用时,清空数组,某一部分元素无法同步的BUG
    • fix IE6-9下addClass没有对类名进行trim操作的BUG
    • fix 短路与,短路或引发的收集依赖失败的BUG
    • 重构scanAttr, fix ms-repeat与ms-css, ms-data共存而漏扫的问题
    • avalon.modern.js去掉HTML Imports的实现,收拾大写变小写引发的BUG
    • fix date filter BUG
    • fix 内部onTree BUG,可能会引起死循环,详见这里
    • fix html filter,详见 这里
    • 优化 CG回收 ms-if ms-hover ms-active 都加上rollback方便移除绑定
    • onTree在触发里面的事件时,针对change blur事件需要对document.activeElement进行检测
    • 修正ms-class中的占位符的生成方式
    • 修正avalon.fn.data取某些对象属性时被序列化的BUG
    • 修正IE6-8下ms-css-float BUG
    • 优化 计算属性,它再也不用收集视图刷新函数与更新视图了
    • ms-repeat、 ms-each、 ms-with现在完全按照供销渠道那一套来写了, 所有代理VM的产生、消费、回收,存放通过xxxProxyFactory、xxxProxyAgent、 recycleProxies、xxxProxyPool实现。详见这里
    Source code(tar.gz)
    Source code(zip)
  • 1.3.7.3(Jan 27, 2015)

    命途多舛的1.3.7

    • 主要是修改ms-duplex BUG。尝试使用使用selectionchange dragend 等事件监听老版IE input元素的value变动(涉及到点击X时清空,粘贴,剪切, 中文输入法问题)
    • 自带加载器text!插件去掉 HTML Imports实现,因为它不能原样输出
    • fix ms-widget与ms-data同时存在时,ms-data被忽略掉的BUG
    Source code(tar.gz)
    Source code(zip)
  • 1.3.7.2(Jan 27, 2015)

    主要是重构 parseHTML及将所有属性合并到ms-attr-*的后遗症

    • 处理tr元素插入caption元素的BUG
    • addClass没有进行trim操作的BUG
    • fix ms-value不等同于 ms-attr-value BUG
    • .css() 设置background时不再自动转换backgroundColor
    Source code(tar.gz)
    Source code(zip)
  • 1.3.7(May 21, 2015)

    • 【新特征】ms-duplex绑定全面升级,脱胎换骨,如avalon.duplexHooks钩子对象,pipe内部方法。详看这里的例子
    • 【新特征】添加data-include-replace辅助指令 详见这里
    • 【新特征】data-duplex-changed支持第二个参数data详见这里
    • 【新特征】VM的$fire通信机制变成这个样式, all!xxx是不依赖于DOM树向周边VM发出通知; up!xxx与down!xxx是依赖于DOM向上方或向下方的VM发出通知,我们可以return false中止广播; 普通的xxx只能触发当前的VM的$watch回调。
    • 【新特征】添加avalon.scanCallback,允许在某次扫描后触发这些回调。详见这里这里的例子
          avalon.scanCallback = function(fn, group) {
              group = group || "$all"
              var array = scanObject[group] || (scanObject[group] = [])
              array.push(fn)
          }
          avalon.scan = function(elem, vmodel, group) {
              elem = elem || root
              group = group || "$all"
              //.....略
          }
         
    • 【优化】修正 $fire在跨模块通信时无法通知widget组件的BUG(添加了createSinalTower内部方法)
    • 【优化】更改innerRequire内部方法的位置,及设置为空函数,方便用户移除“AMD加载器模块”后也能正常使用
    • 【优化】精简IE6-8下input事件的模拟
    • 【优化】精简 newSetter的逻辑详见这里
    • 【优化】fix HTMLInputElement.prototype.value 的重写
    • 【优化】重构notifySubscribers
    • 【优化】fix getEachProxy BUG 详见这里
    • 【优化】支持生成更多SVG元素
    • 【优化】为对付firefox插件下严格的语法检测,使用全新的获取全局变量window的方法
    • 【优化】修正 ms-src不能加载SWF BUG详见这里
    • 【优化】修正ms-duplex 绑定VM某个子VM的属性,input值修改后没有同步到vm.$model的BUG 详见这里
    • 【优化】修正avalon.mix方法拷贝VBScript对象时抛错的BUG 详见这里
    • 【优化】修正IE6下因为for in循环导致isPlainObject不准的BUG 详见这里
    • 【优化】将ms-if去掉的元素都移动head标签的avalon标签下详见这里
    • 【优化】让date过滤器能像chrome那样支持更多日期格式详见这里
    Source code(tar.gz)
    Source code(zip)
  • 1.3.6(May 21, 2015)

    • 【新特性】添加avalon.isFunction方法,不用多说,大家都知道怎么用,但在IE6-8与W3C下,它的实现是不一样的。待会儿说。
    • 【新特性】添加data-duplex-focus辅助指令, 当ms-duplex位于文本域,密码域,文本区上,添加了此指令,会自动获取焦点,光标位于最后的文本后。详见这里
    • 【新特性】ms-duplex-*添加数据转换功能。详见这里
    • 【优化】重构sanitize过滤器,详见这里这里
    • 【优化】重构html绑定,将会导致内存泄漏的replaceNodes替换掉,这里
    • 【优化】重构if绑定,将会导致内存泄漏的msInDocument、ifSanctuary、 placehoder属性移除掉,详见这里
    • 【优化】重构repeat绑定,将会导致内存泄漏的startRepeat、 endRepeat、 parent、callbackElement属性移除掉,原template属性改成为一个字符串。详见这里
    • 【优化】重构modelFactory,通过静态分析收集监控属性与计算属性及函数间的依赖关系,$watch回调的存放数组与视图刷新函数的存放数组合而为一,详见下面commit 简化计算属性监控数组的订阅数组 对函数内部的监控属性进行依赖收集
    • 【优化】重构avalon.contains,IE6-8下,对游离于DOM树外的文本节点,访问其parentNode,有时会抛错。详见这里
    • 【优化】提高cacheExpr的缓存命中率,详见这里
    • 【优化】重构IE6-8下设置元素透明度,待会儿讲。
    • 【警告】重构avalon.Array.ensure的行为,通过返回值是数字还是undefined判定其是否已经添加新元素,详见这里
    • 【警告】废弃dettachVModels的配置项,详见这里
    Source code(tar.gz)
    Source code(zip)
  • 0.9(Apr 15, 2015)

    0.84 0.85

    • 重新使用082的scanNodes方法,因为有关旧式IE下UI渲染锁死的问题已经解决了。
    • 优化each绑定与Collection
    • 添加CSS3 animationend事件支持
    • 添加ms-with绑定
    • fix IE9-10获取option元素的value的BUG
    • 改良 AMD加载器与jQuery这些在内部使用了全局define方法的库的兼容问题
    • 抽象setNumber方法来处理splice,slice这两个数组方法的参数
    • 分割Configue, AMDLoad, DomReady等模块,让框架的可读性更强
    Source code(tar.gz)
    Source code(zip)
Owner
司徒正美
穿梭于二进制与二次元的JS魔术师
司徒正美
Simple and elegant component-based UI library

Simple and elegant component-based UI library Custom components • Concise syntax • Simple API • Tiny Size Riot brings custom components to all modern

Riot.js 14.7k Jan 4, 2023
The worlds smallest fully-responsive css framework

FLUIDITY A fully responsive css framework that is impossibly small HTML is almost 100% responsive out of the box. This stylesheet patches the remainin

murmurs 1.1k Sep 24, 2022
🌟 DataFormsJS 🌟 A minimal JavaScript Framework and standalone React and Web Components for rapid development of high quality websites and single page applications.

?? Welcome to DataFormsJS! Thanks for visiting! ?? ?? ?? ?? ?? ?? 中文 (简体) 欢迎来到 DataFormsJS Español Bienvenido a DataFormsJS Português (do Brasil) Bem

DataFormsJS 156 Dec 8, 2022
HTML Framework that allows you not to write JavaScript code.

EHTML (or Extended HTML) can be described as a set of custom elements that you can put on HTML page for different purposes and use cases. The main ide

Guseyn Ismayylov 171 Dec 29, 2022
One framework. Mobile & desktop.

Angular - One framework. Mobile & desktop. Angular is a development platform for building mobile and desktop web applications using Typescript/JavaScr

Angular 85.7k Jan 4, 2023
Ember.js - A JavaScript framework for creating ambitious web applications

Ember.js is a JavaScript framework that greatly reduces the time, effort and resources needed to build any web application. It is focused on making yo

Ember.js 22.4k Jan 8, 2023
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

Supporting Vue.js Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome ba

vuejs 201.7k Jan 8, 2023
The tiny framework for building hypertext applications.

Hyperapp The tiny framework for building hypertext applications. Do more with less—We have minimized the concepts you need to learn to get stuff done.

Jorge Bucaran 18.9k Jan 4, 2023
A framework for building native apps with React.

React Native Learn once, write anywhere: Build mobile apps with React. Getting Started · Learn the Basics · Showcase · Contribute · Community · Suppor

Facebook 106.8k Jan 3, 2023
The Backbone Framework

Marionette.js The Backbone Framework Marionette v5 Marionette is dropping its dependency on Backbone. That library is available here: https://github.c

Marionette.js 7.1k Jan 5, 2023
MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers

Derby The Derby MVC framework makes it easy to write realtime, collaborative applications that run in both Node.js and browsers. Derby includes a powe

DerbyJS 4.7k Dec 31, 2022
A JavaScript Framework for Building Brilliant Applications

mithril.js What is Mithril? Installation Documentation Getting Help Contributing What is Mithril? A modern client-side JavaScript framework for buildi

null 13.5k Dec 26, 2022
Better MV-ish Framework

❗ I started working on this project in 2012. React didn't exist, Angular didn't have a stable 1.0 release, Internet Explorer 7, 8, 9 was used by 35% o

Antonio Stoilkov 2.8k Jan 1, 2023
A framework for real-time applications and REST APIs with JavaScript and TypeScript

A framework for real-time applications and REST APIs with JavaScript and TypeScript Feathers is a lightweight web-framework for creating real-time app

Feathers 14.2k Dec 28, 2022
A rugged, minimal framework for composing JavaScript behavior in your markup.

Alpine.js Alpine.js offers you the reactive and declarative nature of big frameworks like Vue or React at a much lower cost. You get to keep your DOM,

Alpine.js 22.5k Dec 30, 2022
The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.

Bootstrap Sleek, intuitive, and powerful front-end framework for faster and easier web development. Explore Bootstrap docs » Report bug · Request feat

Bootstrap 161.1k Jan 4, 2023
Semantic is a UI component framework based around useful principles from natural language.

Semantic UI Semantic is a UI framework designed for theming. Key Features 50+ UI elements 3000 + CSS variables 3 Levels of variable inheritance (simil

Semantic Org 50.3k Jan 3, 2023
Materialize, a CSS Framework based on Material Design

MaterializeCSS Materialize, a CSS Framework based on material design. -- Browse the docs -- Table of Contents Quickstart Documentation Supported Brows

Alvin Wang 38.8k Dec 28, 2022