Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 角度2变化检测和变化检测策略.OnPush_Angular_Zonejs - Fatal编程技术网

Angular 角度2变化检测和变化检测策略.OnPush

Angular 角度2变化检测和变化检测策略.OnPush,angular,zonejs,Angular,Zonejs,我试图理解ChangeDetectionStrategy.OnPush机制 我从读数中得出的结论是,变化检测通过比较旧值和新值来工作。如果对象引用没有更改,则该比较将返回false 然而,似乎在某些情况下,该“规则”被绕过。你能解释一下它是怎么工作的吗 *ngFor自己进行更改检测。每次运行更改检测时,NgFor将调用其ngDoCheck()方法,并在那里检查数组的内容是否已更改 在您的情况下,没有任何更改,因为构造函数是在Angular开始渲染视图之前执行的。 例如,如果您想添加一个按钮,如

我试图理解
ChangeDetectionStrategy.OnPush
机制

我从读数中得出的结论是,变化检测通过比较旧值和新值来工作。如果对象引用没有更改,则该比较将返回false


然而,似乎在某些情况下,该“规则”被绕过。你能解释一下它是怎么工作的吗

*ngFor
自己进行更改检测。每次运行更改检测时,
NgFor
将调用其
ngDoCheck()
方法,并在那里检查数组的内容是否已更改

在您的情况下,没有任何更改,因为构造函数是在Angular开始渲染视图之前执行的。
例如,如果您想添加一个按钮,如

添加
然后单击实际上会导致
ngFor
必须识别的更改

使用
ChangeDetectionStrategy.OnPush将运行组件中的更改检测,因为当

  • 收到绑定事件
    (单击)
  • 更改检测更新了
    @Input()
  • | async
    管道收到一个事件
  • “手动”调用了更改检测

    • 防止
      应用。勾选
      尝试分离changeDetector:

      constructor(private cd: ChangeDetectorRef) {
      
      ngAfterViewInit() {
        this.cd.detach();
      }
      

      好吧,因为我花了整整一个晚上才明白,所以我写了一份简历来解决脑子里的所有问题,这可能会对未来的读者有所帮助。所以,让我们先把一些事情弄清楚:

      变化来自于事件 组件可能有字段。这些字段只有在某种事件之后才会更改,并且仅在该事件之后才会更改

      我们可以将事件定义为鼠标单击、ajax请求、设置超时

      数据从上到下流动 角度数据流是单向的。这意味着数据不会从孩子流向父母。仅从父级到子级,例如通过
      @Input
      标记。使上层组件了解子组件中某些更改的唯一方法是通过事件。这让我们想到:

      事件触发器更改检测 当一个事件发生时,角度框架从上到下检查每个组件,看看它们是否发生了变化如果有任何更改,它会相应地更新视图。

      Angular在触发事件后检查每个组件。假设您在最低级别的组件上有一个单击事件,这意味着它有父级,但没有子级。这种单击可以通过事件发射器、服务等触发父组件中的更改。。安格尔不知道父母是否会改变。这就是Angular在默认情况下触发事件后检查每个组件的原因

      要查看它们是否改变了角度,请使用
      ChangeDetector

      变化检测器 每个组件都附带了一个变更检测器类。它用于检查组件在某些事件后是否已更改状态,并查看是否应更新视图。当事件发生时(鼠标单击等),默认情况下,所有组件都会发生此更改检测过程

      例如,如果我们有一个ParentComponent:

      @Component({
        selector: 'comp-parent',
        template:'<comp-child [name]="name"></comp-child>'
      })
      class ParentComponent{
        name:string;
      } 
      
      更改对象属性 您可能已经注意到,如果更改对象属性,isChanged方法将返回false。确实如此

      let prop = {name:"cat"};
      let oldProp = prop;
      //change prop
      prop.name = "dog";
      oldProp === prop; //true
      
      由于当对象属性可以更改而不在
      changeDetector
      isChanged()
      中返回true时,angular将假定下面的每个组件也可能已更改。因此,它将简单地检查所有组件中的更改检测

      示例:这里我们有一个带有子组件的组件。虽然父组件的更改检测将返回false,但子组件的视图应该很好地更新

      @Component({
        selector: 'parent-comp',
        template: `
          <div class="orange" (click)="person.name='frank'">
            <sub-comp [person]="person"></sub-comp>
          </div>
        `
      })
      export class ParentComponent {
        person:Person = { name: "thierry" };     
      }
      
      // sub component
      @Component({
        selector: 'sub-comp',
        template: `
          <div>
            {{person.name}}
          </div>
      })
      export class SubComponent{
        @Input("person") 
        person:Person;
      }
      
      单击后,名称仍在视图中,但不在组件本身中


      组件内部触发的事件将触发更改检测。 现在我们来谈谈我最初的问题中让我困惑的地方。下面的组件标有OnPush策略,但视图在更改时会更新

      @组件({
      选择器:“我的应用程序”,
      模板:`
      `,
      风格:[`
      .orange{背景:橙色;宽度:250px;高度:250px;}
      `]
      })
      导出类应用程序{
      person:person={name:“thierry”};
      单击(){
      this.person.name=“Jean”;
      console.log(此.sub.person);
      }
      }
      //子组件
      @组成部分({
      选择器:“子组件”,
      changeDetection:ChangeDetectionStrategy.OnPush,
      模板:`
      {{person.name}
      `,
      风格:[`
      .grey{背景:#ccc;宽度:100px;高度:100px;}
      `]
      })
      导出类子组件{
      @输入()
      person:person={name:“jhon”};
      单击(){
      this.person.name=“密歇根”;
      }
      }
      
      这里我们看到对象输入没有改变引用,我们使用的是策略OnPush。这可能会让我们相信它不会被更新。事实上,它是更新的

      正如Gunter在回答中所说,这是因为,使用OnPush策略,在以下情况下,组件会发生变化检测:

      • 在组件本身上接收(单击)绑定事件
      • 更新了@Input()(如ref obj中的更改)
      • |异步管道收到一个事件
      • “手动”调用了更改检测
      不管战略如何

      链接

      在angular中,我们高度使用父子结构。在那里,我们使用@输入将数据从父级传递给子级

      在那里,如果在子级的任何祖先上发生更改,那么更改检测将在该祖先的组件树中发生

      但是在大多数情况下,我们只需要在子对象的输入发生变化时更新子对象的视图(调用变化检测)。为了实现这一点,我们可以使用OnPush@Component({ selector: 'parent-comp', template: ` <div class="orange" (click)="person.name='frank'"> <sub-comp [person]="person"></sub-comp> </div> ` }) export class ParentComponent { person:Person = { name: "thierry" }; } // sub component @Component({ selector: 'sub-comp', template: ` <div> {{person.name}} </div> }) export class SubComponent{ @Input("person") person:Person; }
      @Component({
        selector: 'my-app',
        template: `
          <div class="orange" (click)="click()">
            <sub-comp [person]="person" #sub></sub-comp>
          </div>
        `
      })
      export class App {
        person:Person = { name: "thierry" };
        @ViewChild("sub") sub;
        
        click(){
          this.person.name = "Jean";
          console.log(this.sub.person);
        }
      }
      
      // sub component
      @Component({
        selector: 'sub-comp',
        changeDetection: ChangeDetectionStrategy.OnPush,
        template: `
          <div>
            {{person.name}}
          </div>
        `
      })
      export class SubComponent{
        @Input("person") 
        person:Person;
      }
      
      export interface Person{
        name:string,
      }
      
      @Component({
        selector: 'my-app',
        template: `
          <div class="orange" >
            <sub-comp ></sub-comp>
          </div>
        `,
        styles:[`
          .orange{ background:orange; width:250px; height:250px;}
        `]
      })
      export class App {
        person:Person = { name: "thierry" };      
        click(){
          this.person.name = "Jean";
          console.log(this.sub.person);
        }
        
      }
      
      // sub component
      @Component({
        selector: 'sub-comp',
        changeDetection: ChangeDetectionStrategy.OnPush,
        template: `
          <div class="grey" (click)="click()">
            {{person.name}}
          </div>
        `,
        styles:[`
          .grey{ background:#ccc; width:100px; height:100px;}
        `]
      })
      export class SubComponent{
        @Input()
        person:Person = { name:"jhon" };
        click(){
          this.person.name = "mich";
        }
      }
      
      - The Input reference changes(Immutable inputs)
      - An event originated from the component or one of its children
      - Run change detection explicitly
      - Use the async pipe in the view