angular 列表渲染机制

  watchCollection:监听集合元素的变化,而不能监听到集合元素内部的属性变化,只要集合中元素的引用没有发生变化,则认为无变化。用这个api也可以监听普通对象的第一层属性变化。

  watch:监听数据有没有发生变化,引用有无发生变化、原始类型数值有无发生变化等。除非指定第三个参数为true,否则不会对比对象的内层(多层)属性的变化,而仅仅对比引用。

  ngRepeat的检测 = watchCollection + watch(第三个参数为true)。

  默认情况下,ngRepeat使用列表元素对象的$$haskKey来标识关联对应的dom(angular会为不同引用的对象创建不同的$$hashKey),如果列表元素不是对象而是原始数据类型,则以元素的值来标识。在同一个列表中,标识必须唯一,否则报错,也可以通过track by xx 来自己指定标识的方式,如track by $index 就是用列表的索引来进行标识。

 

  ngRepeat会为每个单元创建一个作用域,然后把当前循环的状态($index,$first等)传递到这个作用域中,因为这个作用域是原型继承于外部作用域的,所以当ngRepeat出现嵌套的时候,可以通过ngInit把外层循环的index记录下来共内层循环使用:

<div ng-repeat="item in ones" ng-init="outerIndex=$index">
   <span  ng-repeat="item in twos" >the outer index is {{outerIndex }}</span> <br>
</div>

列表优化

  默认情况下,当列表中的元素引用发生变化(脏检测时发现的,使用的是watchCollection),angular仅仅会把对应变化的元素item的dom进行移除,然后重新生成一个新的dom替换进去,其余不需要变化。这就意味着当整个列表都发生变化时,整个dom列表会全部移除,生成新的全部替换进去。

  有没有办法改变了列表item的引用,却不生成新的dom进行替换呢?答案是可以的,但要指定track by。以下进行测试:

<body ng-app="app">
    <div ng-repeat="item in ones">{{item}}</div>
    <button ng-click="changeArr()">changeArr</button>
    <button ng-click="getVal()">getVal</button>
</body>
<script>
    var app = angular.module("app",[]);
    app.run(function($rootScope){
        $rootScope.ones = [{a:1},{a:2},{a:3}];

        setTimeout(setVal,100);

        $rootScope.changeArr = function(){
            $rootScope.ones[0] = {a:1,b:2};
        }
        $rootScope.getVal = function(){
            console.log(document.querySelectorAll("div")[0].data)
            console.log(document.querySelectorAll("div")[1].data)
        }
    });
    function setVal(){
        document.querySelectorAll("div")[0].data = 0;
        document.querySelectorAll("div")[1].data = 1;
    }
</script>

以上代码中,点击getVal,输出01,接着点击changeArr,更换了一个列表元素,界面上出现变化,接着点击getVal,输出undefined 1 。

结论:没有使用track by,当列表元素的引用被替换时,对应的dom也会被替换,之前绑定在上面的数据自然也就没了。

接下来使用track by 进行dom复用:

<div ng-repeat="item in ones track by item.a">{{item}}</div>

修改后,点击changeArr,界面发生变化,接着点击getVal,输出01 。

 

根据以上现象总结angular的列表渲染机制:

 

所以优化的策略就是,显式指定track by,能减少dom的创建,有利于dom的复用

 

posted @ 2017-12-19 22:13  HelloHello233  阅读(628)  评论(0编辑  收藏  举报