Heim  >  Artikel  >  Web-Frontend  >  Eingehende Analyse der Angularjs1-Komponentenprogrammierung (mit Beispielen)

Eingehende Analyse der Angularjs1-Komponentenprogrammierung (mit Beispielen)

寻∝梦
寻∝梦Original
2018-09-07 15:19:001795Durchsuche
<p>In diesem Artikel wird hauptsächlich die ausführliche Analyse von <a href="http://www.php.cn/course/47.html" target="_blank">AngularJS vorgestellt.</a>1 Solange Sie es nicht schwierig finden, können Sie AngularJS hier lernen Test für alle. Artikel, werfen wir jetzt einen Blick auf diesen Artikel </p> <h2>Angular 1 benötigt auch komponentenorientierte Programmierung </h2> <p>Front-End-Komponentisierung ist ein unumkehrbarer Trend im Front-End-Entwicklungsmodell . Die drei wichtigsten Front-End-Frameworks <code>angular 2</code> <code>react</code> <code>vue</code> betrachten alle die Komponentenprogrammierung als eines ihrer Hauptverkaufsargumente <code>angular 1</code> Als Framework mit einer relativ langen Geschichte, das vom unehelichen Kind vorangetrieben wird <code>angular 2</code> , es hat endlich Komponenten übernommen, die alten Projekte im Unternehmen haben endlich die Möglichkeit, den Geschmack der komponentenbasierten Programmierung zu erleben. </p> <h2>Der Weg zur Komponentisierung in Angular 1 </h2> <p><code>angular 1</code> Programmierideen, die der Komponentisierung ähneln, gab es tatsächlich schon sehr früh, aber damals wurden sie nicht als Komponenten, sondern als Anweisungen bezeichnet <code>restrict: 'E'</code> macht diese Richtlinie der heutigen Verwendung von Komponenten sehr ähnlich. <code>angular 1.5</code>, die Anweisungen basieren auf ähnlichen Konzepten von <code>angular 2</code> und werden in die heutigen Komponenten wiedergeboren. </p> <h2>Merkmale der Komponenten</h2> <p>In der offiziellen Dokumentation werden die Unterschiede zwischen Komponenten und Anweisungen aufgeführt. Darüber hinaus sollte ein Standardbauteil auch die folgenden Eigenschaften erfüllen. </p> <ol class=" list-paddingleft-2"> <li><p>Der Tag-Name der Komponente muss einen Unterstrich enthalten</p></li> <li><p>Die Komponente hat einen guten Lebenszyklus</p></li> <li> <p>Komponenten sind in sich geschlossen</p> </li> <li><p>Komponenten sind in sich geschlossen</p></li> <li><p>Komponenten sind wiederverwendbar</p></li> <li> <p>Komponenten können angepasst werden </p> </li> </ol> <p>Wie unten erläutert. </p> <h3>Namensspezifikation für Komponenten </h3> <p>Im Gegensatz zu Direktiven müssen Komponenten ein Element sein, und HTML hat hierfür spezielle Spezifikationen. </p> <p>Die HTML-Spezifikation hinterlässt Tags mit Unterstrichen zur Verwendung durch Entwickler. Die auf diese Weise gebildeten Elemente werden auch als benutzerdefinierte Elemente bezeichnet. Obwohl wir das Konzept der benutzerdefinierten Elemente nicht verwendet haben, ist das Verhalten der beiden ähnlich. Diesem Anspruch sollten wir gerecht werden. </p> <p>Diese Spezifikation entspricht <code>angular 1</code>: Der Komponentenname muss in Kamel-Schreibweise angegeben werden. </p> <p>Beispiel: </p> <pre class="brush:php;toolbar:false">module.component('dialog', {     // ... });</pre> <p>Das ist nicht richtig. Die HTML-Spezifikation hat den Standardelementdialog definiert. Die wiederholte Verwendung von Tag-Namen kann dazu führen, dass sich das Verhalten unserer benutzerdefinierten Komponenten mit dem Verhalten des Standardelements vermischt, was zu seltsamen Fehlern führt und Entwickler indirekt daran hindert unter Verwendung des nativen Labels <code>dialog</code>. </p> <p>Auch wenn der Standard ein Element jetzt nicht definiert, bedeutet dies nicht, dass es in Zukunft nicht definiert wird. Da unser Programm im Browser läuft, muss es den Regeln folgen. Dies ist eine legale Schreibweise: </p> <pre class="brush:php;toolbar:false">module.component('customDialog', {     // ... });</pre> <h3>Eigenständigkeit von Komponenten</h3> <p>Eine gut gestaltete Komponente muss ihr eigenes Verhalten und ihren eigenen Standardstil haben. </p> <h4>Standardverhalten</h4> <p>Das Standardverhalten wird in <code>angular 1</code> mithilfe eines Controllers definiert. </p> <pre class="brush:php;toolbar:false">function CustomDialogController($service) {     this.someField = 123;     this.someMethod = function someMethod() {     } } CustomDialogController.$inject = ['$service']; module.component('customDialog', {     controller: CustomDialogController,     template: require('./customDialogTemplate.html'), });</pre> <p>Da die Komponente <code>controllerAs</code> standardmäßig aktiviert, sind alle Variablen und Funktionen an <code>this</code> gebunden, sodass Sie auch die <code>ES2015</code>-Syntax von <code>class</code> verwenden können, um den Code zu organisieren: </p> <pre class="brush:php;toolbar:false">class CustomDialogController {     constructor($service) {     }     someMethod() {     } } CustomDialogController.$inject = ['$service']; module.component('customDialog', {     controller: CustomDialogController,     template: require('./customDialogTemplate.html'), });</pre> <p>Ein Problem dabei ist, dass andere Funktionen den in <code>constructor</code> injizierten Dienst nicht nutzen können und nur einmal über <code>this</code> übertragen werden können. Mein persönlicher Ansatz ist dieser: </p> <pre class="brush:php;toolbar:false">class CustomDialogController {     constructor($service) {         this.services = { $service };     }     someMethod() {         const { $service } = this.services;     } } // 下略</pre> <p> empfiehlt die Verwendung von <code>function</code>-Definitionen für Controller von Komponenten mit relativ einfacher Logik und <code>class</code>-Definitionen für komplexe Komponenten, deren Codeebene klarer und leichter lesbar sein sollte . . </p> <h4>Standardstil </h4> <p>Der Standardstil einer Komponente wird direkt über das Stylesheet festgelegt. </p> <pre class="brush:php;toolbar:false">custom-dialog {     display: block;     // ... }</pre> <p>Standardmäßig werden Inline-Elemente (<code>display: inline</code>) für alle Tags verwendet, die vom Browser nicht erkannt werden, was für Komponenten im Allgemeinen nicht erwünscht ist. Daher verfügen benutzerdefinierte Komponenten normalerweise über mindestens <code>display: (inline-)block</code>, um den Standardanzeigemodus des Elements zu ändern. </p> <h3>Selbstgeschlossenheit der Komponenten</h3> <p>Selbstgeschlossenheit umfasst zwei Aspekte: Selbstgeschlossenheit der Daten und Selbstgeschlossenheit des Stils. </p> <h4>Eigenständigkeit der Daten</h4> <p><code>angular 1</code> Der Bereich der Komponente selbst ist bereits isoliert (isoliert), dh der Bereich der Komponente erbt nicht vom übergeordneten Bereich (<code>__proto__</code> ist <code>null</code>). Darüber hinaus sollte eine kanonische Komponente externe Daten nicht direkt nutzen, da dies die Wiederverwendbarkeit der Komponente zerstört. Um ein paar Beispiele zu nennen: </p> <ol class=" list-paddingleft-2"> <li><p>$rootScope</p></li> <li><p>$root, $parent (in Vorlage)</p></li> <li> <p>Routing-Parameter</p> </li> <li><p>localStorage, sessionStorage</p></li> </ol> <p>Diese Daten sollten durch Parameterbindung übergeben werden<code>binding</code>. Wenn die Komponente von einem Routing-Plug-in generiert wird, kann „resolve“ verwendet werden. </p> <p>Zweitens sollte die Parameterbindung keine bidirektionale Bindung verwenden <code>=</code> und kanonische Komponenten sollten Daten, die außerhalb der Komponente übergeben werden, nicht (direkt) ändern. Es gibt zwei offiziell empfohlene Parameterbindungsmethoden </p> <ol class=" list-paddingleft-2"><li><p><code><</code> 单向绑定,绑定可变数据。通常用于给组件传递数据</p></li><li><p><code>@</code> 字符串绑定,绑定字符串。通常用于指定组件行为</p></li></ol><p>对于单向绑定对象的情况,由于是引用传递,也不应该修改对象内部的属性。</p><p>遇到要向外部传值的情况,推荐使用 ngModel 或 事件绑定(下面会提到)</p><h4>样式的自封闭性</h4><p>组件间的样式不应该互相干扰,这一点可以简单的通过 <code>scss</code> 的样式嵌套(Nesting)实现:</p><pre class="brush:php;toolbar:false">custom-dialog { display: block; // ... .title { // ... } .body { // ... } }</pre><p>这样可以简单的把组件的内置样式表限制在组件内部,从而避免样式外溢。但是这种方法对在组件内部的其他组件不起效果。如果这个组件的模板中还引用了别的组件,或者这个组件被定义为可嵌入的(transclude),那么可以考虑加类名前缀:</p><pre class="brush:php;toolbar:false">custom-dialog { display: block; .custom-dialog { &-title { // .. } &-body { } } }</pre><h3>组件的可复用性</h3><p>组件为复用而生,拥有良好自封闭性的组件必然是可复用的,因为这个组件不受任何外部因素干扰。组件的复用形式包括</p><ol class=" list-paddingleft-2"><li><p>一个页面中使用多次</p></li><li><p>在多个页面中使用</p></li><li><p><code>ng-repeat</code></p></li><li><p>自己套自己(递归树结构)</p></li><li><p>整个源代码拷贝到其他项目中</p></li></ol><p>等等。一个高度可复用的组件则可以被称为控件,是可以单独投稿 <code>npm</code> 项目库的。</p><p>当然,有些组件(比如单独的页面)可能复用需求没那么高,可以视组件的复用程度不同,从组件的自封闭性和整体代码量做一些取舍。</p><h3>组件的定制化</h3><p>一个高度可复用的组件一定可以被定制。</p><h4>行为的定制化</h4><p>通过参数绑定实现组件行为的定制化。例如:</p><pre class="brush:php;toolbar:false"><custom-dialog x-title="My Dialog" x-modal="true"><!-- 与标签名一样,自定义属性名也应该使用中划线 -->     <!--content --> </custom-dialog><pre class="brush:php;toolbar:false">module.component('customDialog', {     template: require('./customDialogTemplate.html'),     transclude: true,     bindings: {         title: "@",         modal: '<&#39;, }, });</pre><p>出于使用方便的考虑,定制用的参数都是可选的,组件内部实现应该给每个定制参数设定默认值。(想看更多就到PHP中文网<a href="http://www.php.cn/course/47.html" target="_blank">angularjs学习手册</a>中学习)</p><h4>样式的定制化</h4><p>组件风格定制可以使用 class 判断。</p><pre class="brush:php;toolbar:false">custom-dialog { display: block; // ... .title { font-size: 16px; // ... } &.big { .title { font-size: 24px; } } }</pre><p>使用时</p><pre class="brush:php;toolbar:false"><custom-dialog x-title="My Dialog" class="mydialog big"></custom-dialog></pre> <p>深度定制样式比较好的方式是 CSS 属性(CSS Variable,注意不是 SCSS 属性)。</p> <pre class="brush:php;toolbar:false">custom-dialog {     display: block;     // ...     .title {         font-size: 16px;         color: var(--dialog-title-color, #333);         // ...     }     &.big {         .title {             font-size: 24px;         }     } }</pre> <p>这时只需要文档中说明标题颜色使用 <code>--dialog-title-color</code> 这个 CSS 变量就好,外部使用不依赖于组件内部 DOM 实现。使用时</p> <pre class="brush:php;toolbar:false">.mydialog {     --dialog-title-color: red; }</pre> <h3>组件的生命周期</h3> <p>从创建至销毁,组件有自己的生命周期(lifecycle),而不像指令那样把 scope 作为生命周期。常用的回调函数如下:</p> <ul class=" list-paddingleft-2"> <li><p><code>$onInit()</code>:组件被初始化时调用。与 constructor 不同,<code>angular 1</code> 确保 <code>$onInit</code> 被调用时组件的所有参数绑定都被正确赋值。</p></li> <li><p><code>$onChanges(changeObj)</code>:组件参数绑定值被改变时调用。用于监听绑定值的变化,初次绑定时也会调用这个函数。</p></li> <li><p><code>$onDestroy()</code>:组件被销毁时调用。用于清理内部资源如 <code>$interval</code> 等。</p></li> </ul> <p>这些函数也是绑定在 <code>this</code> 上的。如果 <code>controller</code> 使用 <code>ES2015</code> 的 <code>class</code> 定义方式,可以这么写:</p> <pre class="brush:php;toolbar:false">class CustomDialogController {     constructor() {}     onInit() {}     onChanges({ prop1, prop2 }) {}     onDestroy() {} }</pre> <h2>组件间的通信</h2> <p>组件间通信是一个让很多人头疼的问题,通常有这样 3 种情况</p> <h3>子 -> 父</h3> <p>这种情况有标准的实现方式:事件绑定。例如</p> <pre class="brush:php;toolbar:false">class CustomDialogController {     close($value) {         this.hide = true;         this.onClose({ $value });     } } module.component('customDialog', {     controller: CustomDialogController,     template: require('./customDialogTemplate.html'),     bindings: {         onClose: '&',     }, });</pre> <p>使用时:</p> <pre class="brush:php;toolbar:false"><custom-dialog on-close="$ctrl.handleClose(value)"></custom-dialog></pre> <p>这种方式也可以用于子组件向父组件传值。</p> <h3>父 -> 子</h3> <p>用于触发子组件的某个动作。除了改变某个在子组件内部监听变化的绑定参数值外,行之有效的方式就只有事件广播。</p> <p>子组件先监听某个事件</p> <pre class="brush:php;toolbar:false">$scope.$on('custom-dialog--close', () => this.close());</pre> <p>父组件发送广播</p> <pre class="brush:php;toolbar:false">$scope.$broadcast('custom-dialog--close');</pre> <p>切记:事件是全局性的。当有组件复用的情况时请使用标识指定接收对象(BUS 模型);另外最好给事件名添加组件前缀。</p> <h3>同级组件</h3> <p>请通过父级组件中转</p> <h3>子 -> 某全局性组件</h3> <p>这个显示 Notification 时最常用。遇到这种情况时,可以封装服务(Service)。例如:</p> <pre class="brush:php;toolbar:false">module.component('globalNotification', {     controller: class GlobalNotificationController {         constructor(notificationService) {             notificationService.component = this;         }         show(props) {             // ...         }     } }); module.factory('notify', function NotifyService() {     return {         warn(msg) {             this.show({ type: 'warn', text: msg });         }         error(msg) {             this.show({ type: 'error', text: msg });         }     } });</pre> <p>方案并不完美。如果有更好的建议欢迎提出。</p> <h2>结语</h2> <p>有人可能问既然三大前端框架都是组件化的,何必还要在 <code>angular 1</code> 上实现。殊不知 <code>angular 1</code> 的组件诞生的初衷就是为了减少向 <code>angular 2</code> 迁移的难度。机会总是留给有准备的人,哪天老板大发慈悲表示给你把代码重写的时间,你却看着项目里满屏的 <code>$scope.abc = xxx</code> 不知所措,这岂不是悲剧。。。</p> <p>Dieser Artikel endet hier (wenn Sie mehr lesen möchten, besuchen Sie die PHP-Chinesisch-Website <a href="http://www.php.cn/course/47.html" target="_blank">AngularJS-Lernhandbuch </a>, um mehr zu erfahren. Wenn Sie Fragen haben, können Sie unten eine Nachricht hinterlassen </p> <p class="comments-box-content"></p></code></p></li></ol>

Das obige ist der detaillierte Inhalt vonEingehende Analyse der Angularjs1-Komponentenprogrammierung (mit Beispielen). 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