Heim  >  Artikel  >  php教程  >  AngularJS befasst sich eingehend mit Bereichen, Vererbungsstrukturen, Ereignissystemen und Lebenszyklus

AngularJS befasst sich eingehend mit Bereichen, Vererbungsstrukturen, Ereignissystemen und Lebenszyklus

高洛峰
高洛峰Original
2016-12-08 09:58:371123Durchsuche

Die Beispiele in diesem Artikel beschreiben den Umfang, die Vererbungsstruktur, das Ereignissystem und den Lebenszyklus von AngularJS. Teilen Sie es als Referenz mit allen. Die Details lauten wie folgt:

Ausführliche Diskussion des Scope-Bereichs

Jeder $scope ist eine Instanz der Klasse Scope. Der Klassenbereich verfügt über Methoden, die den Lebenszyklus des Bereichs steuern können, die Möglichkeit zur Weitergabe von Ereignissen bieten und das Rendern von Vorlagen unterstützen.

Bereichshierarchie

Schauen wir uns dieses einfache HelloCtrl-Beispiel noch einmal an:

var HelloCtrl = function($scope){
  $scope.name = 'World';
}

HelloCtrl sieht aus wie ein gewöhnliches Beispiel Tatsächlich gibt es außer dem $scope-Parameter nichts Neues. Aber woher kommt dieser Parameter?

Dieser neue Bereich wird von der ng-controller-Direktive mithilfe der Scope.$new()-Methode generiert. Warten Sie, wir benötigen also mindestens eine Instanz des Bereichs, um einen neuen Bereich zu erstellen! Ja, AngularJS hat tatsächlich einen $rootScope (dies ist der übergeordnete Bereich aller anderen Bereiche). Diese $rootScope-Instanz wird erstellt, wenn eine neue Anwendung gestartet wird. Die

ng-controller-Direktive ist eine der Direktiven, die Bereiche erstellen können. AngularJS erstellt eine neue Instanz der Scope-Klasse, wenn es im DOM-Baum auf diese Anweisung „create-scope“ trifft. Diese neu erstellten Bereiche verweisen über die Eigenschaft „$parent“ auf ihren eigenen übergeordneten Bereich. Es gibt viele Anweisungen im DOM-Baum, die Bereiche erstellen können. Infolgedessen werden viele Bereiche erstellt.

Die Form des Bereichs ähnelt einer baumartigen Eltern-Kind-Beziehung, und die Wurzel ist die $rootScope-Instanz. So wie die Bereichserstellung durch den DOM-Baum gesteuert wird, ahmt auch der Bereichsbaum die Struktur des DOM nach.

Da Sie nun wissen, dass einige Anweisungen neue untergeordnete Bereiche erstellen, fragen Sie sich vielleicht, warum diese ganze Komplexität nötig ist. Um dies zu verstehen, zeigen wir ein Beispiel, in dem die ng-repeat-Schleifenanweisung verwendet wird.

Der Controller ist wie folgt:

var WorldCtrl = function ($scope) {
  $scope.population = 7000;
  $scope.countries = [
    {name: 'France', population: 63.1},
    {name: 'United Kingdom', population: 61.8},
  ];
};

Die Vorlage ist wie folgt:

<ul ng-controller="WorldCtrl">
  <li ng-repeat="country in countries">
    {{country.name}} has population of {{country.population}}
  </li>
  <hr>
  World&#39;s population: {{population}} millions
</ul>

Die ng-repeat-Direktive durchläuft eine Sammlung von Ländern und erstellt ein neues DOM-Element für jedes Element in der Sammlung. Die Syntax der ng-repeat-Direktive ist sehr einfach zu verstehen; jedes Element erfordert eine neue Variable „country“ und hängt diese für die Ansichtswiedergabe an „$scope“.

Aber hier gibt es ein Problem, das heißt, jedes Land muss eine neue Variable in einen $scope einbinden, und wir können den zuvor eingebundenen Wert nicht einfach überschreiben. AngularJS löst dieses Problem, indem es für jedes Element in der Sammlung einen neuen Bereich erstellt. Diese neu erstellten Bereiche sind der passenden DOM-Baumstruktur sehr ähnlich, die wir auch mit der zuvor erwähnten fantastischen Chrome-Erweiterung Batarang visualisieren können.

Jeder Bereich (durch ein Rechteck begrenzt) verwaltet sein eigenes Datenmodell. Es ist absolut kein Problem, Variablen mit demselben Namen zu verschiedenen Bereichen hinzuzufügen, und es treten keine Namenskonflikte auf (verschiedene DOM-Elemente verweisen auf unterschiedliche Bereiche und verwenden die Variablen des entsprechenden Bereichs zum Rendern der Vorlage). Auf diese Weise hat jedes Element seinen eigenen Namensraum. Im vorherigen Beispiel hat jedes 25edfb22a4f469ecb59f1190150159c6-Element seinen eigenen Gültigkeitsbereich und die Ländervariablen sind in ihren jeweiligen Gültigkeitsbereichen definiert.

Hierarchie und Vererbung des Bereichs

Die im Bereich definierten Attribute sind für seine untergeordneten Elemente sichtbar. Stellen Sie sich vor, der untergeordnete Bereich muss nicht wiederholt mit demselben Namen definiert werden. Dies ist in der Praxis sehr nützlich, da wir Eigenschaften, die andernfalls über die Bereichskette verfügbar wären, nicht immer wieder neu definieren müssen.

Wenn wir uns das vorherige Beispiel noch einmal ansehen, nehmen wir an, wir möchten diese Länder als Prozentsatz der gesamten Weltbevölkerung anzeigen. Um diese Funktion zu implementieren, können wir eine worldsPercentage-Methode für einen Bereich definieren und sie wie folgt mit WorldCtrl verwalten:

$scope.worldsPercentage = function (countryPopulation) {
  return (countryPopulation / $scope.population)*100;
}

und dann be Diese Methode ist Wird für jede von ng-repeat erstellte Bereichsinstanz wie folgt aufgerufen:

<li ng-repeat="country in countries">
  {{country.name}} has population of {{country.population}},
  {{worldsPercentage(country.population)}} % of the World&#39;s
  population
</li>

Die Vererbungsregeln des Bereichs in AngularJS und des Prototyps in JavaScript. Die Vererbungsregeln sind gleich (wenn Sie ein Attribut lesen müssen, suchen Sie so lange im Vererbungsbaum, bis Sie das Attribut gefunden haben).

Das Risiko der Vererbung durch die Bereichskette

Diese Art der Vererbung durch die hierarchische Beziehung des Bereichs ist sehr intuitiv und beim Lesen von Daten leicht zu verstehen. Beim Schreiben von Daten wird es jedoch etwas kompliziert.

Sehen wir uns einmal an, ob wir eine Variable in einem Bereich definieren, unabhängig davon, ob sie sich in einem untergeordneten Bereich befindet. Der JavaScript-Code lautet wie folgt:

var HelloCtrl = function ($scope) {
};

Der Ansichtscode lautet wie folgt:

<body ng-app ng-init="name=&#39;World&#39;">
  <h1>Hello, {{name}}</h1>
  <div ng-controller="HelloCtrl">
    Say hello to: <input type="text" ng-model="name">
    <h2>Hello, {{name}}!</h2>
  </div>
</body>

Führen Sie diesen Code aus und Sie werden feststellen, dass diese Namensvariable zwar nur im Bereich der obersten Ebene definiert ist, aber in der gesamten Anwendung sichtbar ist! Dies zeigt, dass die Variable von der Bereichskette geerbt wird. Mit anderen Worten: Variablen werden im übergeordneten Bereich definiert und dann im untergeordneten Bereich aufgerufen.

现在,我们一起来看看,如果在 d5fd7aea971a85678ba271703566ebfd 中写点字会发生什么,运行结果你可能会感到吃惊,因为 HelloCtrl 控制器所初始化的作用域创建了一个新的变量,而不是直接去修改$rootScope 实例中的值。不过当我们认识到作用域也只不过是在彼此间进行了原型继承,也就不会觉得那么吃惊了。所有可以用在 JavaScript 对象上的原型继承的规则,都可以同等的用在 作用域 的原型链继承上去。毕竟 Scopes 作用域就是 JavaScript 对象嘛。

在子级作用域中去改变父级作用域上面的属性有几种方法。第一种,我们就直接通过 $parent 属性来引用父级作用域,但我们要看到,这是一个非常不可靠的解决方案。麻烦之处就在于,ng-model 指令所使用的表达式非常严重的依赖于整个DOM结构。比如就在 d5fd7aea971a85678ba271703566ebfd 标签上面的哪里插入另一个 可创建作用域 的指令,那$parent 就会指向一个完全不同的作用域了。

就经验来讲,尽量避免使用 $parent 属性,因为它强制的把 AngularJS 表达式和你的模板所创建的 DOM 结构捆绑在了一起。这样一来,HTML结构的一个小小的改动,都可能会让整个应用崩溃。

另一个解决方案就是,不要直接把属性绑定到 作用域上,而是绑到一个对象上面,如下所示:

<body ng-app ng-init="thing = {name : &#39;World&#39;}">
  <h1>Hello, {{thing.name}}</h1>
  <div ng-controller="HelloCtrl">
    Say hello to: <input type="text" ng-model="thing.name">
    <h2>Hello, {{thing.name}}!</h2>
  </div>
</body>

   

这个方案会更可靠,因为他并没有假设 DOM 树的结构是什么样子。

避免直接把数据绑定到 作用域的属性上。应优先选择把数据双向绑定到对象的属性上(然后再把对象挂到 scope 上)。就经验而言,在给 ng-model 指令的表达式中,你应该有一个点(例如, ng-model="thing.name")。

作用域层级和事件系统

层级关系中的作用域可以使用 event bus(一种事件系统)。AngularJS可以在作用域层级中传播具名的装备齐全的事件。事件可以从任何一个作用域中发出,然后向上($emit)和向下($broadcast)四处传播。

AngularJS核心服务和指令使用这种事件巴士来发出一些应用程序状态变化的重要事件。比如,我们可以监听$locationChangeSuccess 事件(由 $rootScope 实例发出),然后在任何 location(浏览器中就是URL)变化的时候都会得到通知,如下所示:

$scope.$on(&#39;$locationChangeSuccess&#39;, function(event, newUrl, oldUrl){
  //react on the location change here
  //for example, update breadcrumbs based on the newUrl
});

   

每一个作用域对象都会有这个 $on 方法,可以用来注册一个作用域事件的侦听器。这个函数所扮演的侦听器在被调用时会有一个 event 对象作为第一个参数。后面的参数会根据事件类型的不同与事件本身的配备一一对应。

类似于 DOM 事件,我们可以调用 event 对象的 preventDefault() 和 stopPropagation() 方法。stopPropagation() 方法将会阻止事件沿着作用域层级继续冒泡,并且只在事件向上层传播的时候($emit)才有效。

尽管 AngularJS 的事件系统是模仿了 DOM 的,但两个事件传播系统是完全独立的,没有任何共同之处。

虽然在作用域层级中传播事件对一些问题来说是一种非常优雅方案(特别是对全局的,异步的状态变化来说),但还是要适度使用。通常情况下,可以依靠双向数据绑定来得到一个比较干净的方案。在整个 AngularJS 框架中,一共只发出($emit)了三个事件($includeContentRequested,$includeContentLoaded,$viewContentLoaded)和七个广播($broadcast)($locationChangeStart, $locationChangeSuccess, $routeUpdate, $routeChangeStart,$routeChangeSuccess, $routeChangeError, $destroy)。正如你所看到的,作用域事件使用的非常少,我们应该在发送自定义的事件之前认真的评估一下其他的可选方案(多数会是双向数据绑定)。

千万不要在 AngularJS 中模仿 DOM 的基于事件的编程方式。大多数情况下,你的应用会有更好的架构方式,你也可以在双向数据绑定这条路上深入探索。

作用域的生命周期

作用域需要提供相互隔离的命名空间,避免变量的命名冲突。作用域们都很小,而且被以层级的方式组织起来,对内存使用的管理来说很有帮助。当其中一个作用域不再需要 ,它就可以被销毁了。结果就是,这个作用域所暴露出来的模型和方法就符合的垃圾回收的标准。

新的作用域通常是被 可创建作用域 的指令所生成和销毁的。不过也可以使用 $new() 和 $destroy() 方法来手动的创建和销毁作用域。

希望本文所述对大家AngularJS程序设计有所帮助。


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn