AngularJs項目實踐總結
今年3月接觸AngularJs,并且在6月的項目中開始應用,從踩坑到填坑花了不少時間,根據項目中的實際應用情況總結了一些經驗,如下:
一.UI控件選擇
Angularjs是不缺控件的,Github里現成的控件非常豐富,基本上足以應付一個普通管理系統中常見的控件需求。但是控件的豐富會帶來選擇的困難。選擇控件要滿足幾個原則:
原則1:符合業務場景
原則2:控件持續更新
原則3:滿足性能要求
舉幾個例子。首先是上傳附件的控件。項目中要用到附件上傳,谷歌上搜到了三個控件,分別是
https://github.com/leon/angular-upload
https://github.com/danialfarid/ng-file-upload
https://github.com/nervgh/angular-file-upload
因為項目需要兼容IE9,就重點關注了這三個控件對瀏覽器的兼容性。第一個控件沒有任何說明,第二個控件支持IE9,但是前提是要安裝flash,第三個控件支持IE8和9,但是只支持部分功能。從瀏覽器兼容性的角度考慮,最終選擇了控件三。
再舉一個例子,下拉框控件。html原生的select功能比較單一,并且option的樣式很難修改,在前端各個框架所用的下拉框基本上都是重新實現的。Angularjs也不例外。項目中剛開始選用了ui-select2。后來在ui-select2的介紹中看到這句話:
This directive is now obsolete. A new initiative, more active, and 100% angular is available at https://github.com/angular-ui/ui-select.
發現ui-select2已經有3年沒有更新了,果斷棄坑選用ui-select。
最后談談原則3,還是說ui-select吧,它雖然是ui-select2的改進版,但是性能上是存在問題的,根據stackoverflow上的問答,一個ui-select里包含過多選擇項或者一個頁面包含過多ui-select控件時,性能有明顯降低。因為這一點,曾考慮用其他控件替換掉ui-select,不過項目中并不存在大數據量和過多控件的情況,最后仍然保留了它。在滿足原則1和2和前提下,只能盡量滿足原則3。
一個新項目在開發前,最好能根據需求調研可能用到的UI控件,并嘗試寫一些demo,尤其對復雜的UI控件。比如ui-grid,有太多的指令和api,花費在閱讀文檔和官方實例代碼的時間也是一筆不小的投入。
二.自定義指令
自定義的指令要加命名空間(前綴),防止全局指令名污染,就像javascript中防止全局變量污染一樣。在項目中,某個頁面出現了這樣的錯誤:
Error: [$compile:multidir] Multiple directives [refresh, uiSelectChoices] asking for template on: <ui-select-choices repeat="searchRes in searchRes" refresh="searchMedia($select)">
但是新建一個測試用的解決方案,ui-select卻是正常的。幾經搜索,后來才發現在項目公共的directive里定義了一個叫refresh的指令,它和ui-select的refresh指令重名了。
解決辦法很簡單,重命名自定義的refresh指令。
三.頁面防抖動
在頁面初始化的時候,用戶可能會先看到 {{ }},然后閃爍一下才出現真正的內容。這是因為Angularjs會在dom加載完后才會解析{{ }}中的內容,在這之前,{{ }}不是Angularjs的插值表達式,而是文本。
解決辦法:
1. 在要顯示的內容上使用 ng-cloak指令,并且添加如下樣式
<style> [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { display: none !important; } </style>
2. 使用 ng-bind 替代 {{ }}
四.模塊化思維
Angularjs推薦模塊化開發,module的本意即是模塊化,但是在Angularjs 1.X中,module更多體現出來的是一個“命名空間”的概念,而不是真正意義上的模塊化。比如A模塊依賴B模塊,B模塊應該是一個獨立的東西,但是被A引用之后,A、B模塊中的指令,服務,控制器全部混在了一起,使用指令、控制器時甚至不需要指定是哪個模塊中的指令和控制器。在Angularjs2中已經拋棄了module,ES6也引入了javascript底層的模塊化。在模塊化這方面,不必按照Angularjs 1.X鋪好的路走。
在項目中,我們的做法是,整個單頁面應用是一個module,每個頁面對應一個controller和view,公共的功能寫在service中(這點還需要改進,呵呵)。
controller的定位應該是一個完整且盡可能小的功能模塊。比如一個列表頁,點擊某條記錄后彈窗顯示該記錄的詳細信息,那么列表頁寫一個controller,詳細頁寫另一個controller。controller之間是低耦合的,如果有一定的依賴關系,使用事件廣播與接收進行通訊($emit, $broadcast, $on)。controller是不可復用的。
公共的邏輯寫在service中,并且按功能分類,滿足單一職責。使用時用依賴注入。避免寫成全局的公共方法。
五.懶加載
單頁面應用如果體量較小,完全不需要懶加載,把所有腳本打包壓縮在一起是更好的解決方案。但是體量較大,加載的腳本又多又大,就需要考慮懶加載的方式了。按需加載文件,而不是一次性加載整個應用所需要的全部文件。懶加載的方式推薦用ocLazyLoad,而不要用requireJs。因為requireJs只能加載文件,無法注冊module,controller,directive,而ocLazyLoad不但可以加載文件,也可以完成注冊。配合ui-route的路由管理,實現懶加載非常方便。
六.性能
Angularjs采用臟檢測的方式來檢查對象的變化,與其他框架相比——比如同為MVVM模式的vue.js或者使用了虛擬dom的React——Angularjs的性能并不出眾。但是,開發一個單頁面應用或者一個管理系統,性能完全不是瓶頸。造成Angularjs性能降低的關鍵因素往往是添加了太多的watcher,超過2000(經驗數值)個watcher時,會明顯降低性能。所以提高性能的基本方法就是盡量減少watcher數量,比如使用ng-repeat時限制數組的長度并使用track by,以及一次性數據綁定{{::x}}
七.安全
AngularJs本身不允許不安全的代碼,比如controller中定義一段帶有html標簽的字符串:
$scope.html="<p>text</p>";
在頁面上顯示的是原始的字符串,而不是一個段落。這是Angularjs自身的防XSS攻擊機制。除此另外,作為開發人員,應該注意不要在模版中動態簽入用戶輸入的數據。當然,如果需要顯示html編碼后的內容,也是可以的,使用$sanitize或$sce服務即可。$sanitize會按照Angularjs自身設置的白名單來凈化html,$sce服務包含有$sce.trustAs,$sce.trustAsHtml,$sce.trustAsUrl,$sce.trustAsResourceUrl,$sce.trustAsJs等方法,用于編碼可信任的html標簽。
總結:Angularjs作為當前流行的MVVM框架,開發管理類的CRUD系統真的太合適了。Javascript中一切皆對象,而在Angularjs中可以說一切皆數據,以數據驅動的方式解決dom的更新,提升不少開發效率。本次項目只是Angularjs的首次應用,只接觸到了框架本身的部分功能,希望以后能有更多項目應用Angularjs。另外,Angularjs2已經在9月15日正式發布了,也許某天可以用Angularjs2來開發新的項目~
來自:http://www.cnblogs.com/pilixiami/p/5978631.html