• 迷你MVVM框架 avalonjs 0.85发布


    迷你MVVM框架 avalonjs 0.85发布

    本版本对循环绑定做了巨大改进,感谢@soom, @limodou, @ztz, @Gaubee 提供的大量测试文件。

    • fix scanNodes, 在循环绑定(ms-each)扫描元素节点时必须 nextTick,否则旧式IE会忙碌不过来。
    • fix ms-css ,旧式IE style[name] = value, 当value为NaN ,不带单位或不是数值什么会抛异常,需要try catch。
    • 旧式IE下有些元素的innerHTML是只读的, 因此不能一律使用innerHTML,并且有些元素的生成,如script标签是不会执行,为此我引入新的parseHTML模块来处理此事。
    • fix AMD 加载因为手误进错分支的BUG
    • fix scanExpr bug, 它在IE10有时会多生成一个绑定对象,异致不渲染错误。
    • 重构Collection内部对象与ms-each绑定,引入“事务”的概念,让其插入节点时更加智能高效。

    我们看最后一条,我们可以类似纯JS操作为内存操作,DOM操作为IO操作,执行一万次前者所需的时间可能还比不上一次后者的。DOM操作的开销就是这么大。有的DOM操作还会引起reflow,这危害更大。因此明智的做法就是将要操作的节点移出DOM树。更好的办法是,此多个DOM操作合成一个,全部在文档碎片中搞完才插入DOM树。

    我们看下面的注解:

    <div ms-controller="box">
          <div ms-each-el="array" id="aaa">
               <p>{{$index}}----{{el}}</p>
          </div>
    </div>
    avalon.define("box", function(vm) {
           vm.array = [1, 2, 3, 4, 5]
    })
     
     
    实现过程
    当扫描到div#aaa 将div#aaa的所有子节点复制一份到文档碎片vTemplate
     
    执行begin命令,将vTemplate复制一个空的文档碎片vTransation( cloneNode(false) ), 设置全局变量flagTransation = true;
     
     
        开始循环数组
       
        执行insert命令
        将vTemplate复制一个文档碎片vEl( cloneNode(true) ),
      将对应的子VM与它进行扫描
      此时它的内容应为 <p>0 --- 1</p>
        将vEl appendChild到 vTemplate
        .....
        重复执行array.length次
     
    执行commit命令,将vTemplate append到div#aaa节点中, 设置全局变量flagTransation = false
    重新排列所有$index

    在数组有关添加元素的push, unshift, splice这三个方法中,都调用了add方法,它里面就默认使用事件进行处理。

    array._splice = array.splice
    array.add = function(arr, insertPos) {
        insertPos = typeof insertPos === "number" ? insertPos : this.length;
        notifySubscribers(this, "begin")
        for (var i = 0, n = arr.length; i < n; i++) {
            var el = convert(arr[i])
            var pos = insertPos + i
            this._splice(pos, 0, el)
            notifySubscribers(this, "insert", pos, el)
        }
        notifySubscribers(this, "commit", insertPos)
        if (!this.stopFireLength) {
            return dynamic.length = this.length
        }
    }

    notifySubscribers会向上通知updateListView方法,然后让它执行相关的DOM操作

    case "begin":
        list.vTransation = data.vTemplate.cloneNode(false)
        flagTransation = true
    case "insert":
        //将子视图插入到文档碎片中
        var tmodel = createVModel(pos, el, list, data.args)
        var tview = data.vTemplate.cloneNode(true)
        tmodel.$view = tview
        vmodels = [tmodel].concat(vmodels)
        tmodels.splice(pos, 0, tmodel)
        scanNodes(tview, vmodels);
        data.group = ~~tview.childNodes.length //记录每个模板一共有多少子节点
        list.vTransation.appendChild(tview)
        break
    case "commit":
        pos = ~~pos
        //得到插入位置 IE6-10要求insertBefore的第2个参数为节点或null,不能为undefined
        var insertNode = parent.childNodes[ data.group * pos] || null
        parent.insertBefore(list.vTransation, insertNode)
        flagTransation = false
        resetItemIndex(tmodels)
        break

    嘛,不过这次改动太大了,有关Collection与bindingHandlers["each"]的代码都几乎改清光。另一个值得一提的是VM数组在腓序时,与视图的同步。这里涉及如何让一个数组基于另一个数组进行排序,我的解决方式如下:

      var aaa = [1, 2, 3, 4, 5, 1]
                var bbb = [{v: 2}, {v: 3}, {v: 1}, {v: 1}, {v: 5}, {v: 4}]
                var swapTime = 0
                var isEqual = Object.is || function(x, y) {//主要用于处理NaN 与 NaN 比较
                    if (x === y) {
                        return x !== 0 || 1 / x === 1 / y;
                    }
                    return x !== x && y !== y;
                };
                for (var i = 0, n = bbb.length; i < n; i++) {
                    var a = aaa[i];
                    var b = bbb[i]
                    var b = b && b.v ? b.v : b
                    if (!isEqual(a, b)) {
                        console.log(++swapTime)
                        var index = getIndex(a, bbb, i);
                        var el = bbb.splice(index, 1)
                        bbb.splice(i, 0, el[0])
                    }
                }
                function getIndex(a, bbb, start) {
                    for (var i = start, n = bbb.length; i < n; i++) {
                        var b = bbb[i];
                        var check = b && b.v ? b.v : b
                        if (isEqual(a, check)) {
                            return i
                        }
                    }
                }
                console.log(JSON.stringify(bbb))
    //在框架中,aaa为数据模型M中的数组,bbb为视图模型VM中的数组

    如果有更好的算法,请多多指教。

    经过这次大重构后,avalon在API上基本没有变化了,未来的v0.9就是fix BUG然后发布正式版。

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

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

    大家可以加入QQ群:79641290进行讨论,此群为技术群,禁水!

     
     
     
    标签: avalon
  • 相关阅读:
    【转】商业内幕(Business Insider)网站近期评出了全美20家最具创新力的科技创业公司
    【转】SQL Server如何截断(Truncate)和收缩(Shrink)事务日志
    【转】xp_dirtree储存过程漏洞
    【转】锻炼胸肌
    【转】sql server 版本中r2解释
    【转】生活感悟
    jquery插件学习之元素顶部悬浮
    html5学习
    javascript 学习之自定义滚动条加滚轮事件
    PHP连接数据库的方法
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3190719.html
Copyright © 2020-2023  润新知