使用了angularJS就離不開jQuery

[b]引言:angularjs是一箇中等重量級的前端開發框架[/b]
HTML是一門很好的爲靜態文本設計的語言,但要構建動態的web應用它就顯的乏力了。通常,我們使用以下技術來解決靜態網頁技術在構建動態應用上的不足:

1.類庫:類庫是一類函數的集合,它能幫助你寫web應用。這裏起主導作用是你的代碼,由你來決定何時使用類庫。典型的類庫,例如prototype、jquery等。

2.框架:框架式一種特殊的、已經實現的web應用,你只需要填充具體的業務邏輯。這裏框架是起主導作用的,由它根據具體的邏輯來調用你的代碼。典型的框架例如knockout,sproutcore, YUI等。angularjs也是其中之一。

框架又有輕重之分。我對輕重的判斷標準是,是否需要很多的第三方類庫來幫助你實現功能。顯然,backbone這種屬於輕量級框架,它簡單易用,專注於前端Mvc的實現,故而你還需要很多第三方類庫(至少jquery)來完成dom操作、UI等各種各樣的內容。Yui、dojo屬於重型框架,他們的作者企圖搞出一個森羅萬象的框架+組件庫,包括代碼動態調用、各種UI組件都包含在內,學習成本較高,但是一旦精通,至少這個項目別無所求。從這個角度講,輕量級框架好比毛坯房,還需要各種工具做裝修,但是對於開發者來說也更靈活。重量級框架好比精裝修的房間,你只需要的是適應它,但如果要自己做出大刀闊斧的修改,那就稍微有點傷經動骨了。

angularjs,在我看來是介於以上兩類之間,是個中等重量級的框架。即不像backbone那麼簡單,也不像dojo和Yui那麼包羅萬象。很多時候,妄圖包羅萬象,往往會出現很多子模塊的質量高不成低不就,並且修改起來較爲困難。過分精簡,則框架內容單薄需要寫的內容太多。angularjs這種相對中庸的風格,則非常符合我的需求。目前,AngularJS三個我認爲最爲精妙的組件就是數據綁定(Scope),指令(Directive)和依賴注入(Dependency Injection),表現得非常好。相對而言,它的UI組件和動畫則是弱項。可以說,選擇了angularjs,就意味着選擇了jquery式的組件庫方式來彌補它的不足,要完成一個web應用必須跟第三方類庫打交道。

現在已經有許多針對angularjs寫的UI插件,有的是結合了bootstrap,有的是結合了jquery, 雖然不太完善,都很值得參考:http://angular-ui.github.io/


與jquery類庫的協作

第三方類庫中,不得不提的是大名鼎鼎的jquery,現在基本上已經是國內web開發的必修工具了。它靈活的dom操作,讓很多web開發人員欲罷不能。再加上已經很成熟的jquery UI 庫和大量jquery 插件,幾乎是一個取之不盡用之不竭的寶庫。然而,它是否能與angularjs結合呢?

很多angularjs原教旨主義者對此持否定態度。他們認爲,既然已經使用了angularjs做web應用框架,那就必須避免其他類庫的干擾,做純淨的MvvM模式應用。任何類似jquery的dom操作,都是不潔的。把所有和界面相關的, 比如dom操作, 都放在directive中, 這樣頁面中directive而沒有代碼,跟JSF思想一致。MVVM,DSL,組件化的思想這纔是web的趨勢。嗯,想法很好,原教旨主義者想法都是這麼純潔。但事實情況是,使用了angularjs我們就離不開jquery。

衆所周知,angularjs裏面事實上已經內置了jquery lite.,而且angularjs源碼中很多方法直接就是使用jquery方法。例如angularjs的事件綁定機制。既然先知們都在用,我們又何苦不用?組件化的思想沒有錯,但沒必要因此把自己的手腳綁住。唯一要注意的問題是,不要用jquery的代碼破壞了angularjs的結構。對此我的原則如下,不足之處還請指出:

[b](1)[/b]模塊劃分、服務、路由、依賴注入等重要方面上都得使用angularjs的方式,只有某些具體內容(通常是一些Ui)才使用jquery。
[b](2)[/b]避免在controller裏面寫了一堆直接操作dom元素的 jquery代碼。使用angularjs的模板綁定機制。
[b](3)[/b]常用的組件要用angularjs的方法抽取出來,但組件具體實現則不必糾結於是否使用jquery及其插件。
[b](4)[/b]使用第三方類庫時,在變量和函數命名時有特殊標記(通常是加上這個類庫名的縮寫)。

jquery,更是建議作爲angularjs的依賴,先於angularjs加載進來。

事實上,選擇了angularjs這樣的框架中德中等重量級選手,就意味着你必須添加其他類庫。而jquery,更是建議作爲angularjs的依賴,先於angularjs加載進來。因爲在查看angularjs API的時候,我已經發現,其中許多功能,事實上是依賴於jquery的。典型的例子,就是官網的ng-blur指令。

〈input type="text" ng-model="name" ng-blur="checkname()" 〉

ng-blur指令,是在焦點離開某個元素時觸發的指令。對於上例,即在焦點離開該文本輸入框時,觸發checkname()函數。

看起來很簡單,但是你如果真的使用了這個指令,你就會發現它根本不起效果。在仔細查看文檔後,我才發現這實際是先知們使用jquery的blur方法實現的函數(而且事實上根本沒有真正實現並放在當前的版本里)。那麼就算我們想寫一個,離開jquery原生庫是不行的,因爲blur方法並未封裝到angularjs內帶的jquery lite裏。換句話說,必須先載入完整的jquery才能使用。於是,我乾脆自己寫了一個標籤:

/*
* angular directive onBlur
*
* @description my ng-blur
* @require jquery
*/
$compileProvider.directive('onBlur', function() {
return {
restrict : 'A',
link : function(scope, elm, attrs) {
elm.bind('blur', function() {
scope.$apply(attrs.onBlur);
});
}
};
});

這已經很好了。

但是還不夠完美。由於$apply方法接受函數的問題,所以直接像上面這樣寫,有可能導致angularjs運行時報錯:$apply already in progress

避免這個問題的發生,則需要對$apply方法進行加工:

/* factory function safeApply
*
* @description If you find yourself triggering the '$apply already in progress' error while developing with Angular.JS
* (for me I find I hit most often when integrating third party plugins that trigger a lot of DOM events),
* you can use a 'safeApply' method that checks the current phase before executing your function.
*
* @param scope, the action scope, mostly is the topmost controller
* @param fn, the function which you want to apply into scope
* @see https://coderwall.com/p/ngisma
*/.factory('safeApply', function($rootScope) {
return function(scope, fn) {
var phase = scope.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if (fn && ( typeof (fn) === 'function')) {
fn();
}
} else {
scope.$apply(fn);
}
}
});

那麼之前的onblur標籤,就應該改爲:

/*
* angular directive onBlur
*
* @description my ng-blur
* @require jquery
*/
$compileProvider.directive('onBlur', function(safeApply) {
return {
restrict : 'A',
link : function(scope, elm, attrs) {
elm.bind('blur', function() {
safeApply(scope, attrs.onBlur);
});
}
};
});

以上代碼我已經加入了自己的angular_extend模塊,在自己的項目中使用了,效果很好。


將jquery 插件用angularjs的方式封裝成組件的例子

icheck是一個jquery插件,用於跨瀏覽器美化Checkbox和Radio按紐。關於它的介紹,在http://www.bootcss.com/p/icheck/

一般來說,它的使用方法是在dom載入後加一段jquery代碼:

$('input').iCheck({
labelHover : false,
cursor : true,
checkboxClass : 'icheckbox_square-blue',
radioClass : 'iradio_square-blue',
increaseArea : '20%'
});

但是既然要放在我們的項目裏,就不能到處塞這種直接操作dom的jquery代碼,既不美觀,也不易維護。按照之前所說的原則,最好將其封裝成angular指令的模式,放在公共模塊裏來調用。這裏我將我新建的指令命名爲ng-icheck。如此,我們只要寫在某個checkbox或者radio的html標籤里加上一句ng-ickeck即可。具體實現如下:

/*
* angular directive ng-icheck
*
* @description icheck is a plugin of jquery for beautifying checkbox & radio, now I complied it with angular directive
* @require jquery, icheck
* @example <input type="radio" ng-model="paomian" value="kangshifu" ng-icheck>
* <input type="checkbox" class="icheckbox" name="mantou" ng-model="mantou" ng-icheck checked>
*/
$compileProvider.directive('ngIcheck', function($compile) {
return {
restrict : 'A',
require : '?ngModel',
link : function($scope, $element, $attrs, $ngModel) {
if (!$ngModel) {
return;
}
//using iCheck
$($element).iCheck({
labelHover : false,
cursor : true,
checkboxClass : 'icheckbox_square-blue',
radioClass : 'iradio_square-blue',
increaseArea : '20%'
}).on('ifClicked', function(event) {
if ($attrs.type == "checkbox") {
//checkbox, $ViewValue = true/false/undefined
$scope.$apply(function() {
$ngModel.$setViewValue(!($ngModel.$modelValue == undefined ? false : $ngModel.$modelValue));
});
} else {
// radio, $ViewValue = $attrs.value
$scope.$apply(function() {
$ngModel.$setViewValue($attrs.value);
});
}
});
},
};
});

在以上代碼中值得注意的是:使用了icheck插件後,會生成一個美化過的div覆蓋在原來的checkbox或者radio之上,而原來的checkbox或者radio會被影藏。故而,當我們點擊它們時,不會直接觸發事件,使得綁定到checkbox或者radio上的model值改變。所以我們這裏需要重新綁定事件,使用

$ngModel.$setViewValue()

方法來給model賦值。具體邏輯,則相根據checkbox和radio而不同。詳見以上代碼。

由於以上代碼寫在我的項目中的通用模塊common_angular_component.js裏,故而在調用了該通用模塊的頁面裏,直接使用ng-icheck指令即可實現ickeck的美化效果,同時避免了大量重複的jquery代碼的出現。

<input type="radio" ng-model="paomian" value="kangshifu" ng-icheck>
<input type="checkbox" name="mantou" ng-model="mantou" ng-icheck checked>


本文固定鏈接: [url]http://www.storagelab.org.cn/zhangdi/2013/09/09/angularjs%e9%a1%b9%e7%9b%ae%e5%ae%9e%e6%88%98%ef%bc%8103%ef%bc%9aangularjs%e4%b8%8e%e5%85%b6%e4%bb%96%e7%b1%bb%e5%ba%93%e7%9a%84%e5%8d%8f%e4%bd%9c/[/url]
發佈了117 篇原創文章 · 獲贊 2 · 訪問量 9019
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章