Heim  >  Artikel  >  Web-Frontend  >  Wie erstelle ich eine benutzerdefinierte Direktive in AngularJS? Detaillierter Prozess zum Erstellen benutzerdefinierter Anweisungen mit AngularJS

Wie erstelle ich eine benutzerdefinierte Direktive in AngularJS? Detaillierter Prozess zum Erstellen benutzerdefinierter Anweisungen mit AngularJS

寻∝梦
寻∝梦Original
2018-09-07 15:04:121259Durchsuche

Dokumentation übersetzt nach angularjs.org Die Dokumentation erklärt, wann Sie Ihre eigenen Anweisungen in Ihrer AngularJS-Anwendung erstellen möchten und wie Sie diese implementieren. Schauen wir uns gemeinsam diesen Artikel an

Was ist ein Befehl?

Auf einer hohen Ebene handelt es sich bei Direktiven um Markups auf einem DOM-Element (als Attribute, Elementnamen, Anmerkungen und CSS-Klassen), die verwendet werden, um den HTML-Compiler ($compile) von Angularjs anzuweisen, diesem DOM-Element ein bestimmtes Verhalten zuzuweisen. (zum Beispiel über Event Listening) oder sogar um ein DOM-Element und seine untergeordneten Elemente zu transformieren.

Angularjs verfügt über eine Reihe integrierter Implementierungen wie ngBind, ngModel und ngClass. Zusätzlich zu den von Ihnen erstellten Controllern und Diensten können Sie Ihre eigenen Anweisungen erstellen, die Angularjs beim Start verwenden kann (Bootstraps). ) Ihrer Anwendung durchläuft der HTML-Compiler die DOM-Übereinstimmungsanweisungen, die den DOM-Elementen entsprechen.

Was bedeutet es, eine HTML-Vorlage zu „kompilieren“? Für AngularJS bedeutet „Kompilierung“ das Anhängen von Anweisungen an den HTML-Code, um ihn interaktiv zu machen Der rekursive Prozess des Anhängens von Direktiven spiegelt den Prozess des Kompilierens von Quellcode in kompilierten Programmiersprachen wider.

Direktivenabgleich
Bevor wir mit dem Schreiben von Direktiven beginnen, müssen wir wissen, wie der HTML-Code verwendet wird Compiler bestimmt

Ähnlich wie bei der Terminologie, die verwendet wird, wenn ein Element mit einem Selektor übereinstimmt, sagen wir, dass ein Element mit einer Direktive übereinstimmt, wenn die Direktive Teil seiner Deklaration ist.

Im folgenden Beispiel sagen wir, dass das <input>-Element mit der ngModel-Direktive

<input> <!-- as an attr -->

übereinstimmt. Das folgende <input>-Element entspricht auch dem ngModel:

<input>

Die folgenden

<person>{{name}}</person>

Normalisierung (vorläufige Übersetzungsnormalisierung)

AngularJS normalisiert die Tag- und Attributnamen von Elementen, um zu bestimmen, welche Elemente mit welchen Anweisungen übereinstimmen. Normalerweise definieren (verweisen) wir eine Direktive anhand ihres kanonisierten Namens (z. B. ngModel), bei dem die Groß-/Kleinschreibung beachtet wird. Da bei HTML jedoch die Groß-/Kleinschreibung nicht berücksichtigt wird, beziehen wir uns auf Anweisungen im DOM in Kleinbuchstaben und verwenden normalerweise den Bindestrich (-) als Trennzeichen, um verschiedene Wörter zu trennen (z. B. ng-model).

Der Normalisierungsprozess ist wie folgt :
1. Entfernen Sie x-, data- am Anfang des Elements/Attributs;
2. Konvertieren Sie -, _,: Trennzeichen in camelCased camelCas
Die folgenden Formen sind alle gleichwertig Dasselbe wie bei ngBind-Direktiven:

  Hello <input> 


   
   
   
   
   

Direktiventyp

A - attributes    <p> </p>
C - class name    <p> </p>
E - element name   <person></person>
M - comments    <!-- directive: person -->

Best Practice: Verwenden Sie Direktiven über Tag-Namen und Attribute gegenüber Kommentaren und Klassennamen. Dies erleichtert im Allgemeinen die Bestimmung mit welchen Anweisungen ein bestimmtes Element übereinstimmt.

Best Practice: Kommentaranweisungen wurden häufig an Stellen verwendet, an denen die DOM-API die Möglichkeit einschränkt, Anweisungen zu erstellen, die sich über mehrere Elemente erstrecken (z. B. innerhalb von

Elemente) . AngularJS 1.2 führt ng-repeat-start und ng-repeat-end als bessere Lösung für dieses Problem ein. >Lassen Sie uns zunächst die API für die Registrierung besprechen Anweisungen werden ebenso wie Controller auf Modulen registriert. Um eine Direktive zu registrieren, müssen Sie die module.directive-API verwenden. module.directive akzeptiert einen standardisierten Direktivennamen, gefolgt von einer Factory-Funktion. Diese Factory-Funktion sollte ein Objekt mit verschiedenen Optionen zurückgeben, um der $compile-Direktive mitzuteilen, wie sie sich bei Übereinstimmung verhalten soll.

Die Factory-Funktion wird nur einmal aufgerufen, wenn $conpile zum ersten Mal mit der Direktive übereinstimmt. Hier können Sie etwaige Initialisierungsarbeiten beauftragen. Diese (Werks-)Funktion wird mit $injector.invoke aufgerufen, wodurch sie wie ein Controller injizierbar ist.

Wir gehen einige gängige Direktivenbeispiele durch und tauchen dann in die verschiedenen Optionen und den Kompilierungsprozess ein.

Best Practice: Um Kollisionen mit einem zukünftigen Standard zu vermeiden, ist es am besten, eigene Direktivennamen voranzustellen. Wenn Sie beispielsweise eine -Direktive erstellt haben, wäre es problematisch, wenn HTML7 Dasselbe Element wurde eingeführt. Ein Präfix mit zwei oder drei Buchstaben (z. B. btfCarousel) funktioniert ebenfalls gut. Stellen Sie Ihren eigenen Anweisungen kein ng voran, da sie sonst mit Anweisungen in einer zukünftigen Version von AngularJS in Konflikt geraten könnten.

Als Folgebeispiel verwenden wir das Präfix „my“ (z. B. „myCustomer“). Richtlinie zur Vorlagenerweiterung

Angenommen, Sie haben eine große Vorlage, die Kundeninformationen darstellt. Diese Vorlage wird in Ihrem Code mehrmals wiederholt. Wenn Sie es an einer Stelle ändern, müssen Sie es an mehreren anderen Stellen ändern. Dies ist eine großartige Gelegenheit, Ihre Vorlage mithilfe von Anweisungen zu vereinfachen.

Lassen Sie uns eine Direktive erstellen, die einfach ihren Inhalt durch eine statische Vorlage ersetzt:

Beachten Sie, dass wir in dieser Direktive Bindungen haben. Nachdem $compile

kompiliert und verknüpft hat, wird versucht, Anweisungen für die untergeordneten Elemente des Elements abzugleichen. Das bedeutet, dass Sie Direktiven innerhalb von Direktiven (verschachtelte Direktiven) erstellen können. Wir werden später sehen, wie man ein Beispiel schreibt.

在上面的例子中,我们列出了模板选项(template attribute of return object in factory function),但随着模板大小的增长,这将变得令人讨厌。

Best Practice: Unless your template is very small, it's typically better to break it apart into its own HTML file and load it with the templateUrl option.

如果你熟悉ngInclude,templateUrl就像它一样工作。下面是使用templateUrl代替的相同示例:

templateUrl也可以是一个函数,它返回要加载和用于指令的HTML模板的URL。AngularJS将使用两个参数调用templateUrl函数:指令被调用的元素以及与该元素相关联的attr对象。

Note: You do not currently have the ability to access scope variables from the templateUrl function, since the template is requested before the scope is initialized
注:(要访问socpe上的值,应该在post-link阶段).

Wie erstelle ich eine benutzerdefinierte Direktive in AngularJS? Detaillierter Prozess zum Erstellen benutzerdefinierter Anweisungen mit AngularJS

When should I use an attribute versus an element?  Use an element when you are creating a component that is in control of the template.The common case for this is when you are creating a Domain-Specific Language for parts of your template. Use an attribute when you are decorating an existing element with new functionality.

用元素来使用myCustomer指令时明智的选择,因为你不用一些“customer”行为修饰一个元素,你定义一个元素核心行为作为一个costomer组建。(想看更多就到PHP中文网angularjs参考手册中学习)

隔离指令的Scope

我们以上的myCustomer指令很好,但是它有一个致命缺陷。我们只有在一个给定的scope下使用。

在其目前的实现上,我们应该需要去创建一些不同点控制器用来重用这个指令。
https://plnkr.co/edit/CKEgb1e...

这明显不是一个好的解决方案。

我们说项的是把指令内部的scope与外部scope(controller scope)分离,并且映射外部scope到指令内部scope。我们可以通过创建一个isolate scope来做。为此,我们可以使用指令的scope选项。

https://plnkr.co/edit/E6dTrgm...
看index.html文件,第一个元素绑定info属性值为naomi,它是我们已经暴露在我们的控制器上的scope。第二个绑定info为igor。

让我们仔细看看scope选项

//... 
scope: { customerInfo: '=info' },
//...

除了可以将不同的数据绑定到指令中的作用域外,使用isolated scope还有其他作用。

我们可以通过添加另一个属性vojta来展示,到我们的scope并尝试从我们的指令模板中访问它:
https://plnkr.co/edit/xLVqnzt...

请注意{{vojta.name}}和{{vojta.address}}为空,意味着它们未定义(undefined)。虽然我们在控制器中定义了vojta,但它在指令中不可用。

顾名思义,该指令的 isolate scope隔离了除显式添加到作用域的模型之外的所有内容:scope: {}散列对象. 这在构建可重用组件时很有用,因为它可以防止组件改变模型状态,除了显式传入。

Note: Normally, a scope prototypically inherits from its parent. An isolated scope does not. See the "Directive Definition Object - scope"section for more information about isolate scopes.

Best Practice: Use the scope option to create isolate scopes when making components that you want to reuse throughout your app.

创建一个操纵DOM的指令

在这个例子中,我们将建立一个显示当前时间的指令。每秒一次,它会更新DOM以反映当前时间。

想要修改DOM的指令通常使用link选项来注册DOM监听器以及更新DOM。它在模板被克隆之后执行,并且是放置指令逻辑的地方。

link接受一个带有一下签名的函数function link(scope, element, attrs, controller, transcludeFn) { ... }, 其中:

  • scope是一个Angularjs scope 对象

  • element 是一个此指令匹配的jqLite包装元素

  • attrs是一个具有标准化属性名称及其对应属性值的键值对的散列对象。

  • controller是指令所需的控制器实例或其自己的控制器(如果有的话)。确切的值取决于指令的 require属性。

  • transcludeFn是预先绑定到正确的包含范围的transclude链接函数。

For more details on the link option refer to the $compile API page.

In unserer Link-Funktion möchten wir die angezeigte Zeit jede Sekunde aktualisieren, oder ein Benutzer ändert die an unseren Befehl gebundene Zeitformatzeichenfolge. Wir werden den Dienst $interval verwenden, um den Handler regelmäßig aufzurufen. Dies ist einfacher als die Verwendung von $timeout, eignet sich aber auch besser für End-to-End-Tests, bei denen wir sicherstellen möchten, dass alle $timeouts abgeschlossen sind, bevor wir den Test abschließen. Wenn die Direktive entfernt wird, möchten wir auch $interval entfernen, damit kein Speicherverlust entsteht
https://plnkr.co/edit/vIhhmNp...

Es gibt einige Dinge, die hier zu beachten sind. Genau wie bei der module.controller-API werden Funktionsparameter in module.directive durch Abhängigkeiten injiziert. Wir können also $interval und dateFilter in der Link-Funktion der Direktive verwenden.

Wir registrieren ein Ereignis element.on('$destroy', ...). Was löst dieses $destroy-Ereignis aus?

AngularJS veröffentlicht einige besondere Ereignisse. Wenn ein mit dem Compiler von AngularJS kompilierter DOM-Knoten zerstört wird, wird das Ereignis $destroy ausgelöst. Wenn ein AngularJS-Bereich zerstört wird, sendet er ebenfalls ein $destroy-Ereignis an die Listening-Bereiche.

Durch das Abhören dieses Ereignisses können Ereignis-Listener entfernt werden, die Speicherverluste verursachen können. Für den Bereich und das Element registrierte Überwachungsereignisse werden automatisch bereinigt, wenn das DOM zerstört wird. Wenn Sie jedoch einen Listener im Dienst registriert haben oder einen Listener auf einem DOM-Knoten registriert haben, der nicht gelöscht wurde, müssen Sie ihn selbst bereinigen, andernfalls Sie Es besteht die Gefahr eines Speicherlecks.

Best Practice: Direktiven sollten nacheinander aufräumen. Sie können element.on('$destroy', ...) oder Scope.$on('$destroy', ...) verwenden. um eine Bereinigungsfunktion auszuführen, wenn die Direktive entfernt wird. Manchmal möchten Sie jedoch in der Lage sein, eine gesamte Vorlage anstelle einer Zeichenfolge oder eines Objekts zu übergeben. Wir sagen, wir möchten eine „Dialogfeld“-Komponente erstellen. Das Dialogfeld sollte die Möglichkeit haben, jeden beliebigen Inhalt umzubrechen.

Dazu müssen wir die Transclude-Option verwenden.

Was genau bewirkt die Transclude-Option? transclude macht den Inhalt der Direktive über diese Option für den Geltungsbereich der externen Direktive und nicht für den internen Geltungsbereich zugänglich.

Um dies zu veranschaulichen, sehen Sie sich das folgende Beispiel an. Beachten Sie, dass wir in script.js eine Link-Funktion hinzugefügt haben, die den Namen in „Jeff“ umdefiniert. Was wird Ihrer Meinung nach mit der {{name}}-Bindung erreicht?

Wie immer dachten wir, {{name}} sollte Jeff sein. Aber was wir sehen, ist Tobias.

Die Transclude-Option ändert die Art und Weise, wie Bereiche verschachtelt werden. Dies führt dazu, dass der Inhalt einer transkludierten Direktive einen beliebigen Bereichsinhalt außerhalb der Direktive und keine internen Bereiche aufweist. Dadurch wird der Inhalt für den externen Bereich zugänglich gemacht.

Bitte beachten Sie, dass, wenn die Direktive keinen eigenen unabhängigen Bereich erstellt, der Bereich in Scope.name = 'Jeff' auf den äußeren Bereich verweist und wir Jeff in der Ausgabe sehen.

Dieses Verhalten ist für Direktiven sinnvoll, die etwas kapseln, da Sie andernfalls jedes Modell, das Sie verwenden möchten, separat übergeben müssen. Wenn Sie jedes gewünschte Modell übergeben müssen, können Sie nicht wirklich beliebige Inhalte verwenden, oder?

Best Practice: Verwenden Sie transclude: true nur, wenn Sie eine Direktive erstellen möchten, die beliebigen Inhalt umschließt.

Als nächstes möchten wir diesem Dialogfeld Schaltflächen hinzufügen, und Ermöglicht Benutzern, die die Direktive verwenden, ihr eigenes Verhalten an das Dialogfeld zu binden.

Wir möchten die von uns übergebene Funktion ausführen, indem wir sie aus dem Geltungsbereich der Direktive aufrufen, aber sie wird im Kontext des registrierten Geltungsbereichs ausgeführt.

Wir haben bereits gesehen, wie man =attr in der Scope-Option verwendet, aber im obigen Beispiel haben wir stattdessen &attr verwendet. Die &-Bindung ermöglicht es einer Direktive, die Auswertung eines Ausdrucks innerhalb eines primitiven Bereichs zu einem bestimmten Zeitpunkt auszulösen. Jeder zulässige Ausdruck ist zulässig, einschließlich eines Ausdrucks, der einen Funktionsaufruf enthält. Daher eignet sich die &-Bindung ideal zum Binden von Callback-Funktionen an Direktivenaktionen.

Wenn der Benutzer im Dialog auf x klickt, wird dank ng-click die Schließfunktion der Direktive aufgerufen. Dieser Close-Aufruf für den isolierten Bereich wertet tatsächlich den Ausdruck hideDialog(message) im Kontext des ursprünglichen Bereichs aus, wodurch die Funktion hideDialog im Controller ausgeführt wird.

Normalerweise wird erwartet, dass Daten vom Isolationsbereich über einen Ausdruck an den übergeordneten Bereich übergeben werden. Dies kann durch Übergabe einer Zuordnung lokaler Variablennamen und -werte an die Ausdrucks-Wrapper-Funktion erfolgen. Beispielsweise akzeptiert die Funktion hideDialkog eine Meldung, die angezeigt wird, wenn das Dialogfeld ausgeblendet ist. Dies wird durch den Direktivenaufruf close({message: 'closing for now'}) angezeigt. Dann wird innerhalb des On-Close-Ausdrucks auf die lokale Variable message zugegriffen (ist verfügbar).

Best Practice: Verwenden Sie &attr in der Scope-Option, wenn Ihre Direktive eine API für die Bindung an Verhaltensweisen verfügbar machen soll .

Erstellen Sie eine Direktive, die einen Ereignis-Listener hinzufügt

Zuvor haben wir Link-Funktionen verwendet, um Direktiven zu erstellen, die ihre DOM-Elemente manipulieren. Aufbauend auf diesem Beispiel erstellen wir eine Direktive, die auf Ereignisse in ihrem Element reagiert.

Was wäre zum Beispiel, wenn wir eine Direktive erstellen möchten, die es dem Benutzer ermöglicht, ein Element zu ziehen?

创建一个通信的指令

你可以组建任何指令通过模板使用他们。

有时,你需要一个由指令组合构建的组件。

想象你想要有一个容器,其中容器的内容对应于哪个选项卡处于活动状态的选项卡。

myPane指令有require选项值为^^myTabs. 当指令使用此选项,&compile将抛出一个错误除非特定的controller被找到。 ^^前缀表示该指令在其父元素上搜索控制器。(^前缀将使指令在自身元素或她的父元素上寻找控制器;又没任何前缀,指令将值操作自身)

所以这个myTabs contoller从哪里来的?指令可以特定一个controllers通过使用 controller选项。如你所见,myTabs指令使用了此选项。就像ngController,此选项附加一个控制器到指令的模板上。

如果需要从模板中引用控制器或绑定到控制器的任何功能,则可以使用选项controllerAs将控制器的名称指定为别名。该指令需要定义要使用的此配置的范围。这在指令被用作组件的情况下特别有用。

回头看myPane的定义,注意到link函数的最后一个参数:tabCtrl。当指令需要控制器时,它将接收该控制器作为其link函数的第四个参数。利用这一点,myPane可以调用myTabs的addPane函数。

如果需要多个控制器,则指令的require选项可以采用数组参数。发送给链接函数的相应参数也将是一个数组。

angular.module('docsTabsExample', [])
.directive('myPane', function() {
  return {
    require: ['^^myTabs', 'ngModel'],
    restrict: 'E',
    transclude: true,
    scope: {
      title: '@'
    },
    link: function(scope, element, attrs, controllers) {
      var tabsCtrl = controllers[0],
          modelCtrl = controllers[1];

      tabsCtrl.addPane(scope);
    },
    templateUrl: 'my-pane.html'
  };
});

明的读者可能想知道链接和控制器之间的区别。基本的区别是控制器可以暴露一个API,并且链接函数可以使用require与控制器交互。

Best Practice: use controller when you want to expose an API to other directives. Otherwise use link.

总结

到此我们已经看了大多数指令的用法,每一个样例演示了一个创建你自己指令的好的起始点。

你可能深入感兴趣于编译过程的解释可以在这里获得compiler guide.

$compile API 有一个全面的指令清单选项以供参考。

最后就是本篇文章到这结束了(想看更多就到PHP中文网angularjs学习手册中学习),有问题的可以在下方留言提问

Das obige ist der detaillierte Inhalt vonWie erstelle ich eine benutzerdefinierte Direktive in AngularJS? Detaillierter Prozess zum Erstellen benutzerdefinierter Anweisungen mit AngularJS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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