AngularJS ng-repeat渲染一次并重复使用

时间:2017-05-18 13:05:23

标签: javascript angularjs performance

我的AngularJS应用程序的视图大量使用ng-repeat指令。它是这样完成的:

<div ng-repeat="branches in company">
    <p>{{branches.name}}</p>
    <p>{{branches.location}}</p>
    <div>
        <select ng-model="branches.officeInformationType">
            <option ng-repeat="offices in branches">{{offices.type}}</option>
        </select>

        <select ng-model="branches.officeInformationMeters">
            <option ng-repeat="offices in branches">{{offices.meters}}</option>
        </select>

        <select ng-model="branches.officeInformationColor">
            <option ng-repeat="offices in branches">{{offices.color}}</option>
        </select>
    </div>
</div>

事实上,第二个ng-repeat和它之后的其他(分支中的办公室)实际上每次都是相同的,因此不需要为每个分支重新计算。它需要绑定到它所包含的行,以便以后保存它,所以branches.officeInformation模型仍然应该通过angular观察,但我想让整个程序更高效。

我正在使用angular-ui-router,当我改变我的“选择你的办公室”视图与其他任何视图之间的视图时,滞后是巨大的,几乎在离开“选择你的办公室”的等待时间的一分钟页。它呈现的速度足够快,整个渲染时间为2秒,但是当我离开页面时,需要花费大量时间才能切换到另一个视图。

任何想法,考虑到ng-model绑定“branches.officeInformation ..”是重要的?

编辑:我已经尝试删除嵌套的ng-repeats,并且对于我删除的每个ng-repeat,状态之间的转换越来越快。当我删除所有嵌套的ng-repeats时,转换变为瞬间,因此我认为它与ng-repeats有关。

ng-repeats由$ index跟踪,在可能的情况下,我使用::进行一次绑定。

感谢。

3 个答案:

答案 0 :(得分:1)

我们可以在用户与之交互之前懒惰加载下拉列表选项。

首先,我们仅使用所选选项初始化每个下拉列表,以便在下拉列表关闭时看到它。

然后我们在每个下拉列表中附加ng-focus指令。当我们的回调触发时,我们可以:

  • 完全填充该下拉列表的选项
  • 从之前有效的下拉列表中删除除所选选项以外的所有选项

我不完全确定数据的结构(看起来某些数组上有其他属性)。所以我选择创建&#34;查看模型&#34;表示UI的对象。您可以根据自己的结构进行调整。

控制器:

// Set up some test office options (null for no selection)

var allOffices = [null];

for (var i = 0; i < 50; i++) {
    allOffices.push(i);
}

// activeDropdown holds the dropdown that is currently populated with the full list
// of options. All other dropdowns are only populated with the selected option so
// that it shows when the dropdown is closed.

var activeDropdown;

$scope.company = [
    // Branch 1
    [
        // These objects represent each dropdown
        {
            // Just the selected option until the user interacts with it
            options: ["0"],
            selected: "0"
        }, {
            // Just the selected option until the user interacts with it
            options: ["1"],
            selected: "1"
        }, {
            // Just the selected option until the user interacts with it
            options: [null],
            selected: null
        }
    ],
    // Branch 2
    [
        // These objects represent each dropdown
        {
            // Just the selected option until the user interacts with it
            options: ["2"],
            selected: "2"
        }, {
            // Just the selected option until the user interacts with it
            options: ["3"],
            selected: "3"
        }, {
            // Just the selected option until the user interacts with it
            options: [null],
            selected: null
        }
    ]
];

// When the user interacts with a dropdown:
//   - fully populate the array of options for that dropdown 
//   - remove all but the selected option from the previously active dropdown's 
//     options so that it still shows when the dropdown is closed

$scope.loadOffices = function (dropdown) {
    if (activeDropdown === dropdown) {
        return;
    }

    dropdown.options = allOffices;

    if (activeDropdown) {
        activeDropdown.options = [activeDropdown.selected];
    }

    activeDropdown = dropdown;
};

模板:

<div ng-repeat="branch in company">
    <div ng-repeat="dropdown in branch">
        Selected: {{ dropdown.selected }}
        <select ng-focus="loadOffices(dropdown)" ng-model="dropdown.selected">
            <option ng-repeat="o in dropdown.options">{{ o }}</option>
        </select>
    </div>
</div>

请注意,我测试时,ng-focus是我需要应用于每个下拉列表的唯一指令。但是,您可能需要添加ng-keydownng-mouseoverng-click或其他内容,以使其在包括移动设备在内的所有方案中都能正常运行。

我也注意到了潜在的样式问题。当您专注于下拉列表时,我们会加载该下拉列表的所有选项。这可能会导致下拉列表的宽度发生变化,因此如果您可以为所有这些宽度设置相同的宽度,那么您应该是好的。

如果每个下拉列表中的选项数量很大,我们可以通过编写一些交互的自定义​​指令进一步优化,并允许共享实际的DOM元素选项。但我怀疑在这个例子中我们不得不走得那么远。

答案 1 :(得分:0)

您是否曾尝试过$ index&#39; ?它会减少有角度的手表开销。

类似的东西:

div ng-repeat="branches in company track by $index">
    <p>{{branches.name}}</p>
    <p>{{branches.location}}</p>
    <div>
        <select ng-model="branches.officeInformationType">
            <option ng-repeat="offices in branches track by $index">{{offices.type}}</option>
        </select>

        <select ng-model="branches.officeInformationMeters">
            <option ng-repeat="offices in branches track by $index">{{offices.meters}}</option>
        </select>

        <select ng-model="branches.officeInformationColor">
            <option ng-repeat="offices in branches track by $index">{{offices.color}}</option>
        </select>
    </div>
</div>

答案 2 :(得分:0)

首先,感谢那些帮助我找到答案的人。

问题是我嵌套了太多的ng-repeats,每个重复元素都附加了太多的事件处理程序。 ng模型,ng-changes和ng-clicks真的很重,但元素的数量也失控了。

我通过使用单个选择而没有任何嵌套的ng-repeats解决了这个问题,这个选择(和选项)是一个模态视图,因此是一个不同的控制器。从该控制器返回选择结果,只有一个选择页面中的所有元素。当从模态返回数据时,我从视图的主控制器中使用它。

再次感谢。