如何让 Angular 2/4 更新现有的 DOM 节点而不是删除+创建它们? [英] How do I get Angular 2/4 to update existing DOM nodes instead of deleting+creating them?

查看:28
本文介绍了如何让 Angular 2/4 更新现有的 DOM 节点而不是删除+创建它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的 Angular 4 应用程序有一个具有 refresh 方法的组件,该方法从我的网络服务中提取一个大对象,如下所示:

DTO/模型类型:

class NuclearReactorStatus {公共反应器名称:字符串;公共冷却杆:CoolingRodStatus[];//1024个元素的数组}类 CoolingRodStatus {公共rodId:数字;公共温度:数字;公共状态:字符串;}

NuclearReactorDisplayComponent内部:

public reactorStatus:NuclearReactorStatus;刷新():无效{this.http.get().订阅(状态 =>{this.reactorStatus = 状态;},错误 =>{控制台错误(错误);});}

在我的 nuclearreactordisplay.component.html

里面

Reactor {{reactorStatus.reactorName}}

<h2>冷却棒</h2><ol *ngIf="reactorStatus.coolingRods"><li *ngFor="let rod of reactorStatus.coolingRods"[data.rod-id]="rod.rodId"[data.rod-temperature]="rod.temperature"class="{{ rod.temperature <100 ? "cool" : rod.temperature <1000 ? "warm" : rod.temperature <10000 ? "hot" : "jalapeno" }}"><span>{{rod.rodId}}</span></ol>

我正在通过将它们排列成网格来对杆

  • 元素进行样式化:

    ol {显示:弹性;flex-wrap: 包裹;列表样式:无;宽度:计算(32 * 16px);//网格是 32 个元素宽,32x32 == 1024}李{显示:块;宽度:16px;高度:16px;过渡:背景色0.2s;}里跨{显示:无;}li.cool { 背景色:黑色;}li.warm { 背景色:橙色;}li.hot { 背景色:黄色;}li.jalapeno { 背景色:红色;}

    注意我使用了transition:background-color,所以杆的盒子的背景颜色会逐渐变化而不是突然变化.

    当我运行我的程序时,我注意到 Angular 实际上替换

      和所有子
    1. 元素数据刷新而不是使用现有 DOM 并更新 class 属性 - 所以我的 background-color 转换从未发生 - 但更令人震惊的是我计算机上的 CPU 使用率猛增,因为以这种方式操作 DOM 的代价.

      我如何让 Angular 重新使用它在模板中创建的

      1. 元素,而不是删除并重新创建它们刷新周期?

        解决方案

        由于 ngFor 在数据列表很大时可能会执行不好,Angular 提供了一个 trackBy 您可以告诉 angular 如何替换现有的 DOM 元素.在此处查看详细信息.

          <li *ngFor="let rod of reactorStatus.coolingRods; trackBy: trackByFun"[data.rod-id]="rod.rodId"[data.rod-temperature]="rod.temperature" class="{{ rod.temperature <100 ? "cool" : rod.temperature <1000 ? "warm" : rod.temperature <10000 ? "hot":墨西哥胡椒"}}"><span>{{rod.rodId}}</span></ol>

        TrackByFun:

        //假设您想在 rodId 更改时重新生成 DOM 元素.trackByFun(索引:数字,杆){返回rod.rodId;}

        My Angular 4 application has a Component that has a refresh method that pulls-in a large object from my web-service, like so:

        DTOs/Model types:

        class NuclearReactorStatus {
        
            public reactorName: string;
            public coolingRods: CoolingRodStatus[]; // array of 1024 elements
        }
        
        class CoolingRodStatus {
            public rodId      : number;
            public temperature: number;
            public status     : string;
        }
        

        Inside the NuclearReactorDisplayComponent:

        public reactorStatus: NuclearReactorStatus;
        
        refresh(): void {
        
            this.http.get<NuclearReactorStatus>()
                .subscribe(
                    status => {
                        this.reactorStatus = status;
                    },
                    err => {
                        console.error( err );
                    }
                );
        }
        

        Inside my nuclearreactordisplay.component.html

        <h1>Reactor {{reactorStatus.reactorName}}</h1>
        
        <h2>Cooling rods</h2>
        <ol *ngIf="reactorStatus.coolingRods">
            <li *ngFor="let rod of reactorStatus.coolingRods"
                [data.rod-id]="rod.rodId"
                [data.rod-temperature]="rod.temperature"
                class="{{ rod.temperature < 100 ? "cool" : rod.temperature < 1000 ? "warm" : rod.temperature < 10000 ? "hot" : "jalapeno" }}"
            >
                <span>{{rod.rodId}}</span>
            </li>
        </ol>
        

        I'm styling the rod <li> elements by arranging them into a grid:

        ol {
            display: flex;
            flex-wrap: wrap;
            list-style: none;
            width: calc( 32 * 16px ); // grid is 32 elements wide, 32x32 == 1024
        }
        li {
            display: block;
            width: 16px;
            height: 16px;
        
            transition: background-color 0.2s;
        }
        li span {
            display: none;
        }
        
        li.cool     { background-color: black; }
        li.warm     { background-color: orange; }
        li.hot      { background-color: yellow; }
        li.jalapeno { background-color: red; }
        

        Note my use of transition: background-color so the rod's box's background color changes gradually instead of suddenly.

        When I run my program, I notice that Angular actually replaces the <ol> and all child <li> elements each time the data refreshes instead of using the existing DOM and updating the class attributes - so my background-color transition never happens - but more alarmingly the CPU usage on my computer skyrockets because of the expense of manipulating the DOM this way.

        How do I get Angular to re-use the <ol> and <li> elements it created in the template instead of deleting and recreating them on every refresh cycle?

        解决方案

        Since ngFor may preform bad when the data list is huge, Angular has provided a trackBy which you can tell angular how to replace existing DOM elements. See details here.

        <ol *ngIf="reactorStatus.coolingRods">
          <li *ngFor="let rod of reactorStatus.coolingRods; trackBy: trackByFun"
            [data.rod-id]="rod.rodId"
            [data.rod-temperature]="rod.temperature" class="{{ rod.temperature < 100 ? "cool" : rod.temperature < 1000 ? "warm" : rod.temperature < 10000 ? "hot" : "jalapeno" }}">
            <span>{{rod.rodId}}</span>
          </li>
        </ol>
        

        TrackByFun:

        // assume you want to regenerate DOM element when rodId changed.
        trackByFun(index: number, rod) { 
          return rod.rodId;               
        }
        

        这篇关于如何让 Angular 2/4 更新现有的 DOM 节点而不是删除+创建它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆