目錄
angular 1 也要以元件為導向
angular 1 的元件化之路
元件的特性
元件的名稱規格
元件的自包含性
預設行為
預設樣式
元件的自封閉性
資料的自封閉性
样式的自封闭性
组件的可复用性
组件的定制化
行为的定制化
样式的定制化
组件的生命周期
组件间的通信
子 -> 父
父 -> 子
同级组件
子 -> 某全局性组件
结语
首頁 web前端 js教程 Angularjs1的深度解析之元件化程式設計(內附實例)

Angularjs1的深度解析之元件化程式設計(內附實例)

Sep 07, 2018 pm 03:19 PM
angular.js javascript

<p>本篇文章主要的介紹了<a href="http://www.php.cn/course/47.html" target="_blank">angularjs</a>1的深度解析,大家不要覺得難,只要不覺得難,那麼你在angularjs這裡算是學的可以了,這可是考驗大家的一篇文章,現在就讓我們一起來看這篇文章吧</p> <h2 id="angular-也要以元件為導向">angular 1 也要以元件為導向</h2> <p>前端元件化是前端開發模式中一個不可逆的趨勢,三大主要前端框架<code>angular 2</code> <code>react</code> <code>vue</code> 都不約而同的把組件化編程作為自己的一大賣點,<code>angular 1</code> 作為一個歷史相對悠久的框架,在私生子<code>angular 2</code> 的推動下,終於也搭上了組件化編程的末班車,公司裡那些老項目終於也有機會體驗組件化編程的滋味。 </p> <h2 id="angular-的元件化之路">angular 1 的元件化之路</h2> <p><code>angular 1</code> 中類似元件化的程式設計思想其實很早就有,只不過那時候不叫元件,而叫指令(Directive),指定<code>restrict: 'E'</code> 後這個指令就與現今元件的用法很相似了。在 <code>angular 1.5</code> 中,又將指令根據 <code>angular 2</code> 的類似概念加以限制,脫胎為如今的元件(Components)。 </p> <h2 id="元件的特性">元件的特性</h2> <p>官方文件列舉了元件和指令的不同點。除此之外,一個規範的組件還應符合以下幾個特點。 </p> <ol class=" list-paddingleft-2"> <li><p>元件的標籤名稱必須包含中劃線</p></li> <li><p>#元件擁有良好的生命週期</p></li> <li><p>元件有自包含性</p></li> <li><p>元件有自封閉性</p></li> <li><p> 元件有可重複使用性</p></li> <li><p>#元件可以被客製化</p></li> </ol> <p>下面依序說明。 </p> <h3 id="元件的名稱規格">元件的名稱規格</h3> <p>與指令不同,元件必須是元素,HTML 對於這一點有特殊的規格。 </p> <p>HTML 規範把帶有中劃線的標籤留給開發者使用,這樣形成的元素又稱為自訂元素(Custom Element)。我們雖然沒有用到自訂元素的概念,但兩者的行為是相似的。我們應該符合這項標準。 </p> <p>這一點規格對應到 <code>angular 1</code> 中即為:元件名稱必須帶有駝峰形式。 </p> <p>例如:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">module.component('dialog', {     // ... });</pre><div class="contentsignin">登入後複製</div></div> <p>這是不對的。 HTML 規範已經定義了dialog 這個標準元素,重複使用標籤名稱可能導致我們自訂的元件行為和標準元素的行為混雜到一起,導致奇葩bug;而且如果這樣做也間接導致開發者不能使用原生的<code>dialog</code> 標籤。 </p> <p>另外,就算現在標準沒有定義某個元素,不代表將來不會定義。我們的程式既然跑在瀏覽器裡,就要照規矩辦事。這是一種合法的寫法:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">module.component('customDialog', {     // ... });</pre><div class="contentsignin">登入後複製</div></div> <h3 id="元件的自包含性">元件的自包含性</h3> <p>一個設計良好的元件一定有它自己的行為和預設樣式。 </p> <h4 id="預設行為">預設行為</h4> <p>預設行為在 <code>angular 1</code> 中以控制器(Controller)定義。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">登入後複製</div></div> <p>因為元件預設啟用<code>controllerAs</code>,所有變數和函數都是綁定到<code>this</code> 上的,所以你也可以使用<code>ES2015</code>的<code>class</code> 語法來組織程式碼:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">class CustomDialogController {     constructor($service) {     }     someMethod() {     } } CustomDialogController.$inject = ['$service']; module.component('customDialog', {     controller: CustomDialogController,     template: require('./customDialogTemplate.html'), });</pre><div class="contentsignin">登入後複製</div></div> <p>這樣做有一個問題就是其他函數不能使用<code>constructor</code> 裡注入的服務(Service),只能透過<code>this</code> 中轉一次。我個人的做法是這樣:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">class CustomDialogController {     constructor($service) {         this.services = { $service };     }     someMethod() {         const { $service } = this.services;     } } // 下略</pre><div class="contentsignin">登入後複製</div></div> <p>建議對於邏輯相對簡單的元件的控制器使用<code>function</code> 定義,複雜的元件使用<code>class</code> 定義,後者程式碼的層次要更為清晰易讀。 </p> <h4 id="預設樣式">預設樣式</h4> <p>元件的預設樣式直接使用樣式表指定。 </p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">custom-dialog {     display: block;     // ... }</pre><div class="contentsignin">登入後複製</div></div> <p>對於所有瀏覽器不認識的標籤,預設都是內嵌元素(<code>display: inline</code>),對於元件來說通常不是想要的。所以自訂的元件通常至少要有 <code>display: (inline-)block</code> 來改變元素的預設顯示方式。 </p> <h3 id="元件的自封閉性">元件的自封閉性</h3> <p>自封閉性包含兩個面向:資料的自封閉性和樣式的自封閉性。 </p> <h4 id="資料的自封閉性">資料的自封閉性</h4> <p><code>angular 1</code> 中,元件本身的scope 已經是隔離的(isolate),即元件的scope 不繼承自父級scope( <code>__proto__</code> 為<code>null</code>)。除此之外,一個規範的元件不應該直接使用外部的數據,因為這樣會破壞元件的可重複使用性。舉幾個例子:</p> <ol class=" list-paddingleft-2"> <li><p>$rootScope</p></li> <li><p>#$root、$parent(範本中)</p></li> <li><p>路由參數</p></li> <li><p>localStorage、sessionStorage</p></li> </ol> <p>這些資料都應該透過參數綁定<code>binding</code> 傳入。如果元件是路由插件生成,那麼可以用 resolve。 </p> <p>其次,參數綁定不應使用雙向綁定 <code>=</code>,規範的元件不應(直接)修改元件外部傳入的資料。官方推薦的參數綁定方式有兩種</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 id="样式的自封闭性">样式的自封闭性</h4><p>组件间的样式不应该互相干扰,这一点可以简单的通过 <code>scss</code> 的样式嵌套(Nesting)实现:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">custom-dialog { display: block; // ... .title { // ... } .body { // ... } }</pre><div class="contentsignin">登入後複製</div></div><p>这样可以简单的把组件的内置样式表限制在组件内部,从而避免样式外溢。但是这种方法对在组件内部的其他组件不起效果。如果这个组件的模板中还引用了别的组件,或者这个组件被定义为可嵌入的(transclude),那么可以考虑加类名前缀:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">custom-dialog { display: block; .custom-dialog { &-title { // .. } &-body { } } }</pre><div class="contentsignin">登入後複製</div></div><h3 id="组件的可复用性">组件的可复用性</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 id="组件的定制化">组件的定制化</h3><p>一个高度可复用的组件一定可以被定制。</p><h4 id="行为的定制化">行为的定制化</h4><p>通过参数绑定实现组件行为的定制化。例如:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">登入後複製</div></div><p>出于使用方便的考虑,定制用的参数都是可选的,组件内部实现应该给每个定制参数设定默认值。(想看更多就到PHP中文网<a href="http://www.php.cn/course/47.html" target="_blank">angularjs学习手册</a>中学习)</p><h4 id="样式的定制化">样式的定制化</h4><p>组件风格定制可以使用 class 判断。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">custom-dialog { display: block; // ... .title { font-size: 16px; // ... } &.big { .title { font-size: 24px; } } }</pre><div class="contentsignin">登入後複製</div></div><p>使用时</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"><custom-dialog x-title="My Dialog" class="mydialog big"></custom-dialog></pre><div class="contentsignin">登入後複製</div></div> <p>深度定制样式比较好的方式是 CSS 属性(CSS Variable,注意不是 SCSS 属性)。</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">登入後複製</div></div> <p>这时只需要文档中说明标题颜色使用 <code>--dialog-title-color</code> 这个 CSS 变量就好,外部使用不依赖于组件内部 DOM 实现。使用时</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">.mydialog {     --dialog-title-color: red; }</pre><div class="contentsignin">登入後複製</div></div> <h3 id="组件的生命周期">组件的生命周期</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> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">class CustomDialogController {     constructor() {}     onInit() {}     onChanges({ prop1, prop2 }) {}     onDestroy() {} }</pre><div class="contentsignin">登入後複製</div></div> <h2 id="组件间的通信">组件间的通信</h2> <p>组件间通信是一个让很多人头疼的问题,通常有这样 3 种情况</p> <h3 id="子-gt-父">子 -> 父</h3> <p>这种情况有标准的实现方式:事件绑定。例如</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">登入後複製</div></div> <p>使用时:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"><custom-dialog on-close="$ctrl.handleClose(value)"></custom-dialog></pre><div class="contentsignin">登入後複製</div></div> <p>这种方式也可以用于子组件向父组件传值。</p> <h3 id="父-gt-子">父 -> 子</h3> <p>用于触发子组件的某个动作。除了改变某个在子组件内部监听变化的绑定参数值外,行之有效的方式就只有事件广播。</p> <p>子组件先监听某个事件</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">$scope.$on('custom-dialog--close', () => this.close());</pre><div class="contentsignin">登入後複製</div></div> <p>父组件发送广播</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">$scope.$broadcast('custom-dialog--close');</pre><div class="contentsignin">登入後複製</div></div> <p>切记:事件是全局性的。当有组件复用的情况时请使用标识指定接收对象(BUS 模型);另外最好给事件名添加组件前缀。</p> <h3 id="同级组件">同级组件</h3> <p>请通过父级组件中转</p> <h3 id="子-gt-某全局性组件">子 -> 某全局性组件</h3> <p>这个显示 Notification 时最常用。遇到这种情况时,可以封装服务(Service)。例如:</p> <div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">登入後複製</div></div> <p>方案并不完美。如果有更好的建议欢迎提出。</p> <h2 id="结语">结语</h2> <p>有人可能问既然三大前端框架都是组件化的,何必还要在 <code>angular 1</code> 上实现。殊不知 <code>angular 1</code> 的组件诞生的初衷就是为了减少向 <code>angular 2</code> 迁移的难度。机会总是留给有准备的人,哪天老板大发慈悲表示给你把代码重写的时间,你却看着项目里满屏的 <code>$scope.abc = xxx</code> 不知所措,这岂不是悲剧。。。</p> <p>這篇文章到這就結束了(想看更多就到PHP中文網<a href="http://www.php.cn/course/47.html" target="_blank">angularjs學習手冊</a>中學習),有問題的可以在下方留言提問</p> <p class="comments-box-content"></p></code></p></li></ol>

以上是Angularjs1的深度解析之元件化程式設計(內附實例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統 如何使用WebSocket和JavaScript實現線上語音辨識系統 Dec 17, 2023 pm 02:54 PM

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

WebSocket與JavaScript:實現即時監控系統的關鍵技術 WebSocket與JavaScript:實現即時監控系統的關鍵技術 Dec 17, 2023 pm 05:30 PM

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統 如何利用JavaScript和WebSocket實現即時線上點餐系統 Dec 17, 2023 pm 12:09 PM

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統 如何使用WebSocket和JavaScript實現線上預約系統 Dec 17, 2023 am 09:39 AM

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript與WebSocket:打造高效率的即時天氣預報系統 JavaScript與WebSocket:打造高效率的即時天氣預報系統 Dec 17, 2023 pm 05:13 PM

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

簡易JavaScript教學:取得HTTP狀態碼的方法 簡易JavaScript教學:取得HTTP狀態碼的方法 Jan 05, 2024 pm 06:08 PM

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

javascript如何使用insertBefore javascript如何使用insertBefore Nov 24, 2023 am 11:56 AM

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript與WebSocket:打造高效率的即時影像處理系統 JavaScript與WebSocket:打造高效率的即時影像處理系統 Dec 17, 2023 am 08:41 AM

JavaScript是一種廣泛應用於Web開發的程式語言,而WebSocket則是一種用於即時通訊的網路協定。結合二者的強大功能,我們可以打造一個高效率的即時影像處理系統。本文將介紹如何利用JavaScript和WebSocket來實作這個系統,並提供具體的程式碼範例。首先,我們需要明確指出即時影像處理系統的需求和目標。假設我們有一個攝影機設備,可以擷取即時的影像數

See all articles