Maison  >  Article  >  interface Web  >  Pratique de développement angulaire (5) : analyse approfondie de la surveillance des changements

Pratique de développement angulaire (5) : analyse approfondie de la surveillance des changements

不言
不言original
2018-04-02 15:03:181224parcourir

Qu'est-ce que la surveillance des modifications

Lors du développement avec Angular, nous utilisons souvent la liaison dans Angular - liaison d'entrée du modèle à la vue, liaison de sortie de la vue au modèle et liaison entre la vue et le modèle Liaison bidirectionnelle. La raison pour laquelle ces valeurs liées peuvent être synchronisées entre la vue et le modèle est due à la détection des changements dans Angular.

Pour faire simple, la détection de changement est utilisée par Angular pour détecter si les valeurs liées entre la vue et le modèle ont changé. Lorsqu'il est détecté que les valeurs liées dans le modèle ont changé, elle est synchronisée avec la vue. Au contraire, lorsqu'il est détecté que la valeur liée sur la vue change, la fonction de liaison correspondante est rappelée.

La source de la surveillance des changements

La clé de la surveillance des changements est de savoir comment surveiller si les valeurs liées ont changé à la plus petite granularité et dans quelles circonstances ces valeurs liées seront provoquées. changer de drap de laine ? Nous pouvons jeter un œil à plusieurs scénarios couramment utilisés :

Événements : click/hover/...

@Component({
  selector: 'demo-component',
  template: `
    <h1>{{name}}</h1>
    <button (click)="changeName()">change name</button>
  `
})
export class DemoComponent {
    name: string = &#39;Tom&#39;;
    
    changeName() {
        this.name = &#39;Jerry&#39;;
    }
}

Nous lions l'attribut name dans le modèle via des expressions d'interpolation. Lorsque change name按钮 est cliqué, la valeur de l'attribut name est modifiée et le contenu affiché dans la vue modèle change également.

XHR/webSocket

@Component({
  selector: &#39;demo-component&#39;,
  template: `
    <h1>{{name}}</h1>
  `
})
export class DemoComponent implements OnInit {
    name: string = &#39;Tom&#39;;
    
    constructor(public http: HttpClient) {}
    
    ngOnInit() {
        // 假设有这个./getNewName请求,返回一个新值&#39;Jerry&#39;
        this.http.get(&#39;./getNewName&#39;).subscribe((data: string) => {
            this.name = data;
        });
    }
}

Nous avons envoyé une requête Ajax au serveur dans la fonction ngOnInit de ce composant. Lorsque cette requête renvoie le résultat, elle modifiera également la liaison sur le courant. vue modèle. La valeur de l’attribut de nom spécifié.

Times : setTimeout/requestAnimationFrame

@Component({
  selector: &#39;demo-component&#39;,
  template: `
    <h1>{{name}}</h1>
  `
})
export class DemoComponent implements OnInit {
    name: string = &#39;Tom&#39;;
    
    constructor() {}
    
    ngOnInit() {
        // 假设有这个./getNewName请求,返回一个新值&#39;Jerry&#39;
        setTimeout(() => {
            this.name = &#39;Jerry&#39;;
        }, 1000);
    }
}

Nous définissons une tâche planifiée dans la fonction ngOnInit de ce composant. Lorsque la tâche planifiée est exécutée, elle modifiera également la liaison sur la vue actuelle. . La valeur de l'attribut name.

Résumé

  • En fait, il n'est pas difficile de constater que les trois situations ci-dessus ont une chose en commun, à savoir ces événements qui font que la valeur contraignante les changements se produisent tous de manière asynchrone.

  • Angular ne capture pas les changements dans les objets. Il utilise le timing approprié pour vérifier si la valeur de l'objet a été modifiée. Ce timing est l'occurrence de ces événements asynchrones.

  • Ce timing est contrôlé par le service NgZone. Il obtient le contexte d'exécution de l'ensemble de l'application et peut capturer l'occurrence, l'achèvement ou l'exception d'événements asynchrones associés, puis pilote l'implémentation angulaire de mécanisme de suivi des changements.

Mécanisme de traitement de la surveillance des changements

Grâce à l'introduction ci-dessus, nous comprenons à peu près comment la détection des changements est déclenchée, puis comment la surveillance des changements dans Angular est effectuée. Tissu de laine ?

La première chose que nous devons savoir est que pour chaque composant, il existe un moniteur de modifications correspondant ; c'est-à-dire que chaque composant correspond à un changeDetector, que nous pouvons obtenir par injection de dépendances dans le composant <.>. changeDetector

Et nos multiples Composants sont organisés dans une arborescence Puisqu'un Composant correspond à un

, alors les changeDetector sont également organisés dans une arborescence. changeDetector

La dernière chose dont nous devons nous rappeler est que chaque détection de changement commence à la racine de l'arborescence des composants.

Par exemple

Composant enfant :

@Component({
  selector: &#39;demo-child&#39;,
  template: `
    <h1>{{title}}</h1>
    <p>{{paramOne}}</p>
    <p>{{paramTwo}}</p>
  `
})
export class DemoChildComponent {
    title: string = &#39;子组件标题&#39;;
    @Input() paramOne: any; // 输入属性1
    @Input() paramTwo: any; // 输入属性2
}
Composant parent :

@Component({
  selector: &#39;demo-parent&#39;,
  template: `
    <h1>{{title}}</h1>
    <demo-child [paramOne]=&#39;paramOneVal&#39; [paramTwo]=&#39;paramTwoVal&#39;></demo-child>
    <button (click)="changeVal()">change name</button>
  `
})
export class DemoParentComponent {
    title: string = &#39;父组件标题&#39;;
    paramOneVal: any = &#39;传递给paramOne的数据&#39;;
    paramTwoVal: any = &#39;传递给paramTwo的数据&#39;;
    
    changeVal() {
        this.paramOneVal = &#39;改变之后的传递给paramOne的数据&#39;;
    }
}
Dans le code ci-dessus, DemoParentComponent passe 71ac11e340500c31ffd1a26cb704b0b1733dbcdb0cb52d6c005bb34feed27005 est intégrée à DemoChildComponent. Du point de vue de la structure arborescente, DemoParentComponent est le nœud racine de DemoChildComponent et DemoChildComponent est le nœud feuille de DemoParentComponent.

Lorsque nous cliquons sur le bouton de DemoParentComponent, il sera rappelé à la méthode changeVal, puis l'exécution de la surveillance des modifications sera déclenchée. Le processus de surveillance des modifications est le suivant :

Tout d'abord, la détection des modifications démarre à partir de DemoParentComponent Start :

  • Détecter si la valeur du titre a changé : aucun changement n'a eu lieu

  • Détecter si la valeur paramOneVal a changé : Il y a eu un changement (cliquez sur Le bouton appelle la méthode changeVal() pour changer)

  • Détecter si la valeur paramTwoVal a changé : Aucun changement n'a eu lieu

Ensuite, la détection de changement entre dans la feuille Node DemoChildComponent :

  • Détecter si la valeur du titre a changé : aucun changement n'a eu lieu

  • Détecter si paramOne a changé : il a changé (en raison de L'attribut paramOneVal du composant parent a changé)

  • Détecter si paramTwo a changé : aucun changement s'est produit

Enfin, comme DemoChildComponent n'existe plus de nœuds Leaf, la surveillance des modifications mettra donc à jour le DOM et synchronisera les modifications entre la vue et le modèle.

Stratégie de surveillance des changements

Après avoir appris le mécanisme de traitement de la surveillance des changements, vous penserez peut-être que ce mécanisme est un peu trop simple et grossier. S'il y a des centaines ou des milliers de fichiers dans mon application, Si un composant déclenche la surveillance, il doit être re-détecté du nœud racine au nœud feuille.

Ne vous inquiétez pas, l'équipe de développement d'Angular a déjà examiné ce problème. Le mécanisme de détection ci-dessus n'est qu'un mécanisme de détection par défaut. Angular fournit également un mécanisme de détection OnPush (définissez l'attribut de métadonnées changeDetection : ChangeDetectionStrategy.OnPush). ).

OnPush 与 Default 之间的差别:当检测到与子组件输入绑定的值没有发生改变时,变化检测就不会深入到子组件中去

变化监测类 - ChangeDetectorRef

上面说到我们可以修改组件元数据属性 changeDetection 来修改组件的变化监测策略(ChangeDetectionStrategy.Default 或 ChangeDetectionStrategy.OnPush),除了这个,我们还可以使用 ChangeDetectorRef 来更加灵活的控制组件的变化监测。

Angular 在整个运行期间都会为每一个组件创建 ChangeDetectorRef 的实例,该实例提供了相关方法来手动管理变化监测。有了这个类,我们自己就可以自定义组件的变化监测策略了,如停止/启用变化监测或者按指定路径变化监测等等。

相关方法如下:

  • markForCheck():把根组件到该组件之间的这条路径标记起来,通知Angular在下次触发变化监测时必须检查这条路径上的组件。

  • detach():从变化监测树中分离变化监测器,该组件的变化监测器将不再执行变化监测,除非再次手动执行reattach()方法。

  • reattach():把分离的变化监测器重新安装上,使得该组件及其子组件都能执行变化监测。

  • detectChanges():手动触发执行该组件到各个子组件的一次变化监测。

使用方法也很简单,直接在组件中注入即可:

@Component({
  selector: &#39;demo-parent&#39;,
  template: `
    <h1>{{title}}</h1>
  `
})
export class DemoParentComponent implements OnInit {
    title: string = &#39;组件标题&#39;;
    
    constructor(public cdRef: ChangeDetectorRef) {}
    
    ngOnInit() {
        this.cdRef.detach(); // 停止组件的变化监测,看需求使用不同的方法
    }
}

相关推荐:

Angular开发实践(四):组件之间的交互

Angular开发实践(二):HRM运行机制

         

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn