Maison  >  Article  >  interface Web  >  Analyse approfondie de la programmation des composants Angularjs1 (avec exemples inclus)

Analyse approfondie de la programmation des composants Angularjs1 (avec exemples inclus)

寻∝梦
寻∝梦original
2018-09-07 15:19:001748parcourir
<p>Cet article présente principalement l'analyse approfondie de <a href="http://www.php.cn/course/47.html" target="_blank">angularjs</a>1. Ne trouvez pas cela difficile, tant que vous ne trouvez pas cela difficile, alors vous pouvez apprendre Angularjs ici. test pour tout le monde. article, jetons un coup d'œil à cet article maintenant </p> <h2>angular 1 a également besoin d'une programmation orientée composants </h2> <p>La composantisation front-end est une tendance irréversible dans le modèle de développement front-end. . Les trois principaux frameworks front-end <code>angular 2</code> <code>react</code> <code>vue</code> considèrent tous invariablement la programmation de composants comme l'un de leurs principaux arguments de vente <code>angular 1</code> Comme un framework avec une histoire relativement longue, piloté par l'enfant illégitime <code>angular 2</code>. , il a finalement adopté les composants. Le dernier train de programmation basée sur les composants, ces anciens projets de l'entreprise ont enfin l'opportunité de goûter à la programmation basée sur les composants. </p> <h2>La route vers la composantisation dans Angular 1 </h2> <p><code>angular 1</code> Les idées de programmation similaires à la composantisation existaient en fait très tôt, mais à cette époque, elles n'étaient pas appelées composants, mais directives Spécifier <code>restrict: 'E'</code>. rend cette directive très similaire à la façon dont les composants sont utilisés aujourd'hui. <code>angular 1.5</code>, les instructions sont restreintes sur la base de concepts similaires à <code>angular 2</code>, et renaissent dans les composants d'aujourd'hui. </p> <h2>Caractéristiques des composants</h2> <p>La documentation officielle répertorie les différences entre les composants et les instructions. De plus, un composant standard doit également répondre aux caractéristiques suivantes. </p> <ol class=" list-paddingleft-2"> <li><p>Le nom de la balise du composant doit contenir un trait de soulignement</p></li> <li><p>Le composant a un bon cycle de vie</p></li> <li> <p>Les composants sont autonomes</p> </li> <li><p>Les composants sont autonomes</p></li> <li><p>Les composants sont réutilisables</p></li> <li> <p>Les composants peuvent être personnalisés </p> </li> </ol> <p>Comme expliqué ci-dessous. </p> <h3>Spécification du nom des composants </h3> <p>Contrairement aux directives, les composants doivent être un élément, et HTML a des spécifications spéciales pour cela. </p> <p>La spécification HTML laisse des balises avec des traits de soulignement que les développeurs peuvent utiliser. Les éléments formés de cette manière sont également appelés éléments personnalisés. Bien que nous n’ayons pas utilisé le concept d’éléments personnalisés, le comportement des deux est similaire. Nous devrions respecter cette norme. </p> <p>Cette spécification correspond à <code>angular 1</code> : le nom du composant doit être en casse chameau. </p> <p>Par exemple : </p> <pre class="brush:php;toolbar:false">module.component('dialog', {     // ... });</pre> <p>Ce n'est pas bien. La spécification HTML a défini la boîte de dialogue des éléments standard. La réutilisation des noms de balises peut entraîner un mélange du comportement de notre composant personnalisé avec le comportement de l'élément standard, conduisant à des bugs étranges et si cela est fait, cela empêchera également indirectement les développeurs d'utiliser l'élément standard. étiquette <code>dialog</code> native. </p> <p>De plus, même si la norme ne définit pas un élément maintenant, cela ne veut pas dire qu'il ne le sera pas dans le futur. Puisque notre programme s'exécute dans le navigateur, il doit suivre les règles. Il s'agit d'une manière légale d'écrire : </p> <pre class="brush:php;toolbar:false">module.component('customDialog', {     // ... });</pre> <h3>Autonomie des composants</h3> <p>Un composant bien conçu doit avoir son propre comportement et son propre style par défaut. </p> <h4>Comportement par défaut</h4> <p>Le comportement par défaut est défini dans <code>angular 1</code> à l'aide d'un contrôleur. </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>Étant donné que le composant active <code>controllerAs</code> par défaut, toutes les variables et fonctions sont liées à <code>this</code>, vous pouvez donc également utiliser la syntaxe <code>ES2015</code> de <code>class</code> pour organiser votre code : </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>Un problème avec cela est que les autres fonctions ne peuvent pas utiliser le service injecté dans <code>constructor</code> et ne peuvent être transférées qu'une seule fois via <code>this</code>. Mon approche personnelle est la suivante : </p> <pre class="brush:php;toolbar:false">class CustomDialogController {     constructor($service) {         this.services = { $service };     }     someMethod() {         const { $service } = this.services;     } } // 下略</pre> <p> Il est recommandé d'utiliser des <code>function</code> définitions pour les contrôleurs de composants à logique relativement simple, et d'utiliser des <code>class</code> définitions pour les composants complexes. devrait être plus clair. </p> <h4>Style par défaut </h4> <p>Le style par défaut d'un composant est spécifié directement à l'aide de la feuille de style. </p> <pre class="brush:php;toolbar:false">custom-dialog {     display: block;     // ... }</pre> <p> La valeur par défaut est les éléments en ligne (<code>display: inline</code>) pour toutes les balises qui ne sont pas reconnues par le navigateur, ce qui n'est généralement pas souhaité pour les composants. Ainsi, les composants personnalisés ont généralement au moins <code>display: (inline-)block</code> pour modifier le mode d'affichage par défaut de l'élément. </p> <h3>L'auto-fermeture des composants</h3> <p>L'auto-fermeture comprend deux aspects : l'auto-fermeture des données et l'auto-fermeture du style. </p> <h4>Auto-fermeture des données</h4> <p><code>angular 1</code> Dans, la portée du composant lui-même est déjà isolée (isoler), c'est-à-dire que la portée du composant n'hérite pas de la portée parent (<code>__proto__</code> est <code>null</code>). De plus, un composant canonique ne doit pas utiliser directement des données externes, car cela détruirait la réutilisabilité du composant. Pour donner quelques exemples : </p> <ol class=" list-paddingleft-2"> <li><p>$rootScope</p></li> <li><p>$root, $parent (dans le modèle)</p></li> <li> <p>Paramètres de routage</p> </li> <li><p>localStorage, sessionStorage</p></li> </ol> <p>Ces données doivent être transmises via la liaison de paramètres<code>binding</code>. Si le composant est généré par un plug-in de routage, la résolution peut être utilisée. </p> <p>Deuxièmement, la liaison de paramètres ne doit pas utiliser la liaison bidirectionnelle <code>=</code>, et les composants canoniques ne doivent pas (directement) modifier les données transmises en dehors du composant. Il existe deux méthodes de liaison de paramètres officiellement recommandées </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>Cet article se termine ici (si vous souhaitez en savoir plus, rendez-vous sur le site Web PHP chinois <a href="http://www.php.cn/course/47.html" target="_blank">manuel d'apprentissage d'angularjs </a> pour apprendre. Si vous avez des questions, vous pouvez laisser un message ci-dessous </p> <p class="comments-box-content"></p></code></p></li></ol>

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