AngularJS移動開發中的坑匯總

來源:互聯網
上載者:User

標籤:style   http   io   color   os   ar   使用   java   for   

      使用AngualrJs開發移動App已經快半年了,逐漸積累了非常多AngularJS的問題,特別是對於用慣了Jquery的開發人員,轉到AngularJS還是須要克服非常多問題的。不像Jquery那樣側重DOM操作,AngularJS是以視圖模型和雙向繫結為核心的。

       以下的內容如果你已經瞭解前端 MVC 概念,並對 AngularJS 有了一定經驗,剛開始學習的人讀起來可能比較艱深晦澀。本文的總結會涉及部分在行動裝置上特有的問題。

DOM操作的問題

        避免使用 jQuery 來操作 DOM,包含添加元素節點,移除元素節點,擷取元素內容,隱藏或顯示元素。你應該使用 directives 來實現這些動作,有必要的話你還要編寫自己的 directives。

       在網站Web前端開發中,假設你感到非常難改變習慣,那麼考慮從你的網頁中移除 jQuery 吧。真的,AngularJS 中的 $http 服務非常強大,基本能夠替代 jQuery 的 ajax 函數,並且 AngularJS 內嵌了 jQLite —— 它內部實現的一個 jQuery 子集,包括了經常使用的 jQuery DOM 操作方法,事件綁定等等。但這並非說用了AngularJS 就不能用 jQuery 了。假設你的網頁有載入 jQuery 那麼 AngularJS 會優先採用你的 jQuery,否則它會 fall back 到 jQLite。

       假設是移動App或移動Web開發,建議不要引入Jquery了,假設實在須要jquery的某些功能,引入Zepto.js吧。只是請相信我,用了AngularJS,你不會須要Jquery的!

       須要自己編寫 directives 的情況一般是當你使用了第三方的 jQuery 外掛程式。由於外掛程式在 AngularJS 之外對錶單值變更,並不能即時反應到 Model 中。比如我們用得比較多的 jQueryUI datepicker 外掛程式,當你選中一個日期後,外掛程式會將日期文字填到 input 輸入框中。View 改變了,卻並沒有更新 Model,由於$(‘.datepicker‘).datepicker(); 這段代碼不屬於 AngularJS 的管理範圍。我們須要編寫一個directive 來讓 DOM 的改變即時更新到 Model 裡。

var directives = angular.module('directives', []); directives.directive('datepicker', function() {   return function(scope, element, attrs) {       element.datepicker({           inline: true,           dateFormat: 'dd.mm.yy',           onSelect: function(dateText) {               var modelPath = $(this).attr('ng-model');               putObject(modelPath, scope, dateText);               scope.$apply();           }       });   }});

然後在 HTML 中引入這個 directive

<input type="text" datepicker ng-model="myObject.myDateValue" />
       Directive 就是在 HTML 裡寫自己定義的標籤屬性,達到外掛程式的作用,有效補充了HTML的功能。這樣的聲明式的文法擴充了 HTML。建議項目中通用的功能和頁面組件,都封裝成Directive,方便使用和代碼維護。

      須要說明的是,有一個 AngularUI 項目提供了大量的 directive 給我們使用,包含 Bootstrap 架構中的外掛程式以及基於 jQuery 的其它非常熱門的 UI 組件。 AngularJS 的社區如今非常活躍,生態系統健全。

ngOption 中的 value

       這是個大坑。假設你去查看 ngOption 產生的 <select> 中的 <option> 的選項值(每一個 <option value="xxx"> 的 value 部分),那絕對是枉費心機。由於這裡的值永遠都會 是 AngularJS 內部元素的索引,並非你所指定的表單選項值。

   還是要轉變觀念,AngularJS 已經不再用表單進行資料互動了,而是用 Model。使用 $http 來提交 Model,在 php 中則使用 file_get_contents(‘php://input‘) 來擷取前端提交的資料。

Input type=‘number‘的問題

AngularJS有些版本號碼,當輸入框設為 Input type=‘number‘時,在行動裝置上ng-change方法會失效。

{{ }} 的問題

在頁面初始化的時候,使用者可能會看到 {{ }},然後閃爍一下才出現真正的內容。
解決的方法:

  1. 使用 ng-cloak directive 來隱藏它
  2. 使用 ng-bind 替代 {{ }}
將介面與商務邏輯分離

Controller 不應該直接引用 DOM,而應該控制 view 的行為。比如“假設使用者操作了 X,應該發生什麼事情”,“我從哪裡能夠獲得 X?”

Service 在大部分情況下也不應該直接引用 DOM,它應該是一個單例(singletons),獨立於介面,與 view 的邏輯無關。它的角色僅僅是“做 X 操作”。

DOM 操作應該放在 directives 裡面。

盡量複用已有功能

你所寫的功能非常可能 AngularJS 已經實現了,有一些代碼是能夠抽象出來複用的,使用更 Angular 的方式。總之就是非常多 jQuery 的繁瑣代碼能夠被替代。

1.  ng-repeat

ng-repeat 非常實用。當 Ajax 從server獲得資料後,我們常常使用 jQuery (比方上面講過的範例) 向某些 HTML 容器節點中加入很多其它的元素,這在 AngularJS 裡是不好的做法。有了 ng-repeat 一切就變得非常easy了。在你的 $scope 中定義一個數組 (model) 來儲存從server拉取的資料,然後使用 ng-repeat 將它與 DOM 綁定就可以。以下的範例初始化定義了 friends 這個 model

<div ng-init="friends = [{name:'John', age:25}, {name:'Mary', age:28}]">    I have {{friends.length}} friends. They are:    <ul>        <li ng-repeat="friend in friends">            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.        </li>    </ul></div>

2.  ng-show

ng-show 也非常實用。使用 jQuery 來依據條件控制介面元素的顯示隱藏,這非經常見。可是 Angular 有更好的方式來做到這一點。ng-show (以及 ng-hide) 能夠依據布林運算式來決定隱藏和顯示。

對於數組或字串,能夠用strXXXX.length控制顯示,否則在行動裝置上會不正常。

類似的內建 directives 還有 ng-disabled, ng-switch 等等,用於條件控制,文法簡潔,都非常強大。

3.  ng-class

ng-class 用於條件性地給元素加入 class,曾經我們也經經常使用 jQuery 來實現。Angular 中的 ng-class 當然更好用了,範例:

<div ng-class="{ errorClass: isError, warningClass: isWarning, okClass: !isError && !isWarning }">...</div>


在這裡 ng-class 接受一個 object 對象,key 為 CSS class 名,值為 $scope 變數控制的條件運算式,其它類似的內建 directives 還有 ng-class-even 和 ng-class-odd,非常有用。

ng-show和ng-if的使用情境問題

使用ng-show和ng-if都實現控制頁面元素顯示的功能,但2者是不同的,ng-if會動態建立DOM,ng-show僅僅是切換已有DOM的顯示,相當於設定style="display:none",假設使用before和after等css偽類控制顯示效果,可能會出現故障,須要依據情況合理使用ng-show和ng-if。

$watch 和 $apply

AngularJS 的雙向資料繫結是最令人興奮的特性了,然而它也不是全能的魔法,在某些情況下你須要做一些小小的修正。

當你使用 ng-model, ng-repeat 等等來綁定一個元素的值時, AngularJS 為那個值建立了一個 $watch,僅僅要這個值在 AngularJS 的範圍內有不論什麼改變,全部的地方都會同步更新。而你在寫自己定義的 directive 時,你須要定義你自己的 $watch 來實現這樣的自己主動同步。

有時候你在代碼中改變了 model 的值,view 卻沒有更新,這在自己定義事件綁定中常常遇到。這時你就須要手動調用 scope.$apply() 來觸發介面更新。上面 datepicker 的範例已經說明了這一點。第三方外掛程式可能會有 call back,我們也能夠把回呼函數寫成匿名函數作為參數傳入$apply()中。

將 ng-repeat 和其它 directives 結合起來

ng-repeat 非常實用,只是它和 DOM 綁定了,非常難在同一個元素上使用其它 directives (比方 ng-show, ng-controller 等等)。

假設你想對整個迴圈使用某個 directive,你能夠在 repeat 外再包一層父元素把 directive 寫在那兒;假設你想對迴圈內部的每個元素使用某個 directive,那麼把它放到 ng-repeat 的一個子節點上就可以。

Scope的問題

Scope 在 templates 模板中應該是 read-only 的,而在 controller 裡應該是 write-only 的。Scope 的目的是引用 model,而不是成為 model。model 就是我們定義的 JavaScript 對象。

$rootScope 是能夠用的,只是非常可能被濫用

Scopes 在 AngularJS 中形成一定的層級關係,樹狀結構必定有一個根節點。通常我們用不到它,由於差點兒每一個 view 都有一個 controller 以及相相應的自己的 scope。

但偶爾有一些資料我們希望全域應用在整個 app 中,這時我們能夠將資料注入 $rootScope。由於其它 scope 都會繼承 root scope,所以那些注入的資料對於 ng-show 這類 directive 都是可用的,就像是在本地 $scope 中的變數一樣。

當然,全域變數是邪惡的,你必須非常小心地使用 $rootScope。特別是不要用於代碼,而只用於注入資料。假設你非常希望在 $rootScope 寫一個函數,那最好把它寫到 service 裡,這樣只實用到的時候它才會被注入,測試起來也方便些。

相反,假設一個函數的功能不過儲存和返回一些資料,就不要把它建立成一個 service。

子範圍的原型繼承問題

       對於剛開始學習的人,這個也是個大坑啊。範圍變數的繼承是基於javascript原型繼承機制的,在使用涉及到範圍的指令如ng-template,ion-modal等時須要特別注意,相關的尋找順序這裡就不細說了。





AngularJS移動開發中的坑匯總

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.