<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    paulwong

    AngularJS 最佳實踐

    AngularJS 是一個 Web 應用框架,它實現了前端的 MVC 架構,能讓開發人員很方便地實現業務邏輯。

    舉個栗子,要做到下面的效果,以前可能需要寫一連串的 JavaScript 代碼綁定 N 多事件。而使用 AngularJS 框架,一句 JavaScript 都不用寫就能實現了,神奇吧?查看演示。

    angularjs-demo

        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>     <div data-ng-app>         單價: <input type="number" min=0 ng-model="price" ng-init="price = 299">         <br>         數量: <input type="number" min=0 ng-model="quantity" ng-init="quantity = 1">         <br>         總價: {{ quantity * price }}     </div>

    這得益于 AngularJS 中的雙向數據綁定特性(Two Way Data-Binding),將 Model 和 View 自動關聯了起來,在更復雜的業務場景下,還有代碼分離的好處,將 DOM 操作和應用邏輯解耦,非常實用。

    不過沒有銀彈,和其他框架一樣,AngularJS 也有它的局限。CRUD 類型的操作是它所擅長的,想想看以前寫過的管理后臺,幾乎大部分都是從數據庫中讀取數據,然后呈現在頁面上,進行各種增刪改查。AngularJS 約定了一套規范(約定優于配置),于是你可以很便捷地操作數據。而在其他方面,例如開發復雜的 Web 游戲,AngularJS 則是無用武之地了。

    一、AngularJS 中的精美特性

    雙向綁定

    上面的例子已經說明了,我們可以像 PHP Smarty 模板一樣在 HTML 中寫表達式,用 {{ 和 }} 包起來。在 AngularJS 里,View 和 Model 是在 Controller 里面綁定的,所以無論你在 View 的表單中修改了內容,還是在 Controller 里通過代碼修改了 Model 值,兩邊都會即時發生變化,同步更新。因為 AngularJS 會監控 (watch) Model 對象的變化,隨時反映到 View 中。

    Filter

    Filter 類似 Unix 里面的 | 管道概念,AngularJS 把它搬到了前端。還是舉個例子,你們感受一下——

    <div>{{ 9999 | number }}</div> <div>{{ 9999+1 | number:2 }}</div> <div>{{ 9*9 | currency }}</div> <div>{{ 'Hello World' | uppercase }}</div>

    輸出結果:

    9,999 10,000.00 $81.00 HELLO WORLD 

    二、AngularJS 中的一些“坑”

    由于過去寫 JavaScript 的習慣使然,人們很容易掉進一些 AngularJS 的陷阱里。下面的內容假設你已經了解前端 MVC 概念,并對 AngularJS 有了一定經驗,初學者讀起來可能比較艱深晦澀。

    DOM 操作

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

    如果你感到很難改變習慣,那么考慮從你的網頁中移除 jQuery 吧。真的,AngularJS 中的 $http 服務非常強大,基本可以替代 jQuery 的 ajax 函數,而且 AngularJS 內嵌了 jQLite —— 它內部實現的一個 jQuery 子集,包含了常用的 jQuery DOM 操作方法,事件綁定等等。但這并不是說用了AngularJS 就不能用 jQuery 了。如果你的網頁有載入 jQuery 那么 AngularJS 會優先采用你的 jQuery,否則它會 fall back 到 jQLite。

    需要自己編寫 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 中引入這個 direcitve

    <input type="text" datepicker ng-model="myObject.myDateValue" />

    說白了 directive 就是在 HTML 里寫自定義的標簽屬性,達到插件的作用。這種聲明式的語法擴展了 HTML。

    需要說明的是,有一個 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') 來獲取前端提交的數據。

    {{ }} 的問題

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

    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 從服務器獲得數據后,我們經常使用 jQuery (比如上面講過的例子) 向某些 HTML 容器節點中添加更多的元素,這在 AngularJS 里是不好的做法。有了 ng-repeat 一切就變得非常簡單了。在你的 $scope 中定義一個數組 (model) 來保存從服務器拉取的數據,然后使用 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>

    顯示結果

    I have 2 friends. They are:   [1] John who is 25 years old.   [2] Mary who is 28 years old. 

    2. ng-show

    ng-show 也很有用。使用 jQuery 來根據條件控制界面元素的顯示隱藏,這很常見。但是 Angular 有更好的方式來做到這一點。ng-show (以及 ng-hide) 可以根據布爾表達式來決定隱藏和顯示。在 $scope 中定義一個變量:

    <div ng-show="!loggedIn">     點擊 <a href="#/login">這里</a> 登錄 </div>

    類似的內置 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,很實用。

    $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。

    三、AngularJS 項目的目錄結構

    怎樣組織代碼文件和目錄?這恐怕是初學者一開始就會遇到的問題。AngularJS 應用開發的官方入門項目angular-seed,其文件結構是這樣的:

    • css/
    • img/
    • js/
      • app.js
      • controllers.js
      • directives.js
      • filters.js
      • services.js
    • lib/
    • partials/

    這種結構對于一個簡單的單頁 app 來說是可行的,只是一旦代碼中存在多個 Controller 或者 Service,就很難找到想要尋找的對象了。我們可以對文件按照業務邏輯進行拆分,就像下面這樣:

    • controllers/
      • LoginController.js
      • RegistrationController.js
      • ProductDetailController.js
      • SearchResultsController.js
    • directives.js
    • filters.js
    • models/
      • CartModel.js
      • ProductModel.js
      • SearchResultsModel.js
      • UserModel.js
    • services/
      • CartService.js
      • UserService.js
      • ProductService.js

    這種結構把不同的業務功能拆分為獨立的文件,條理清晰,但是仍有一定的局限性。最大的問題是一個業務功能的代碼分布在controllers, models, servers 三個不同目錄下,要從中挑出正確的文件,建立起代碼關聯,還是有些麻煩。按照功能進行模塊化劃分目錄結構,應該要更為合理一些:

    • cart/
      • CartModel.js
      • CartService.js
    • common/
      • directives.js
      • filters.js
    • product/
      • search/
        • SearchResultsController.js
        • SearchResultsModel.js
      • ProductDetailController.js
      • ProductModel.js
      • ProductService.js
    • user/
      • LoginController.js
      • RegistrationController.js
      • UserModel.js
      • UserService.js

    這樣也是適合 RequireJS 等模塊加載器的自然直觀的代碼組織方式。

    參考鏈接:

    posted on 2014-06-05 16:18 paulwong 閱讀(1015) 評論(0)  編輯  收藏 所屬分類: ANGULARJS

    主站蜘蛛池模板: 美女视频黄a视频全免费网站色窝| 女人裸身j部免费视频无遮挡| 国产成人免费视频| 亚洲综合图色40p| 色www永久免费| 亚洲国产精品成人精品无码区在线| 久久WWW免费人成—看片| 精品亚洲视频在线观看| 中文字幕久无码免费久久| 亚洲国产精品国自产拍AV| 免费女人高潮流视频在线观看 | 一本色道久久88亚洲精品综合 | 亚洲av日韩av激情亚洲| 亚洲欧洲日产国码二区首页| 95免费观看体验区视频| 亚洲国产人成在线观看| 妞干网在线免费观看| 日韩毛片免费一二三| 亚洲色精品vr一区二区三区| 香蕉免费一区二区三区| 亚洲va在线va天堂va手机| 我要看免费的毛片| 亚洲免费视频一区二区三区| 久久精品亚洲综合| 成年女人免费v片| 无码日韩人妻AV一区免费l | 最近2019免费中文字幕视频三| 亚洲字幕在线观看| 国产三级免费电影| 成人无码WWW免费视频| 国产精品亚洲精品观看不卡| 国产亚洲色婷婷久久99精品| a级毛片黄免费a级毛片| 亚洲国产成人久久| 国产一区二区三区无码免费| 97超高清在线观看免费视频| 久久www免费人成看国产片| a级毛片毛片免费观看久潮| 免费人成再在线观看网站| 亚洲精品无码永久在线观看男男| 成人片黄网站色大片免费观看cn|