這篇文章主要介紹了jQuery和angularJS的區別淺析,本文着重講解一個熟悉jQuery的程序員如何應對angularJS中的一些編程思想的轉變嗎,須要的朋友能夠參考下jquery
最近一直研究angularJs最大的感覺就是它和以前的jQuery以及jQuery各類庫的設計理念徹底不同。若是不能認識到這一點,而對於以前作jQuery開發的程序員,去直接學習angularJs的話,極可能學了好久還不知道這個東西究竟是什麼,拿來作什麼的,怎麼和UI進行結合等問題,我也是處處找資料看了看,在此把本身學習的一些心得和你們分享一下,以求你們共同進步。程序員
原問題:假如我熟悉利用jQuery去開發客戶端應用,那麼我怎麼上手angularJs,可否描述下所須要的模式轉變,下面這些問題可以幫助你給出一個回答:angularjs
1.在設計客戶端web應用的時候有什麼區別,最大的區別是什麼?web
2.我應該中止使用那些技術,同時又使用哪些技術代替?ajax
3.是否存在服務端須要考慮的東西或者一些限制呢?編程
回答:json
1.不要首先設計好你的頁面,而後再經過Dom操做去修改它架構
在jQuery中,你首先設計了一個page,而後再去動態修改它的內容,這是由於jQuery被設計用來進行擴展並在這個前提下大幅度地增長和修改內容,但在angular中,你必須在心中先設計好你的架構,從一開始,你就要摒棄」我擁有一個Dom元素而且向讓它去作某件事「,代之爲」我須要完成什麼任務,而後接着設計你的應用,最後再去設計你的視圖view層「。併發
2.不要使用angularjs去擴展jQueryapp
相應的,不要存在說讓jQuery去幹某些事情,而後再此基礎上添加angularjs的功能讓它去管理model以及controller的想法。因此我通常不推薦angularjs開發新手同時使用jQuery,至少在他們尚未適應angularjs的開發模式以前不會去推薦這樣作,可是當你真正開始適應angularjs的方式以後,你會發覺這是一件很誘人的事情。
我曾經看過一些開發者採用將150到200行代碼的jQuery插件利用angularjs的回調以及$apply方法封裝起來,這種方式使得代碼看起來頗爲複雜,可是實際上他們讓這些插件跑起來了!問題在於,在大部分狀況下jQuery插件可以用angularjs進行重寫,而且可能用更少的代碼,同時這種重寫使得代碼更直觀,可讀性高,這顯然好過於jQuery的代碼封裝。
因此最後說,當你遇到問題的時候,首先要以angularjs的思惟進行思考,若是找不到解決方案,能夠求助於別人,若是沒有一我的能給出滿意合理的答案,咱們再考女jQuery,不要讓jQuery成爲你的柺杖,不然你永遠掌握不了angularjs.
3.要以架構爲中心進行思考
首先你要知道單頁 的應用屬於web應用,他們不是傳統的多頁網站。因此咱們要同時做爲一個服務端和客戶端開發者的思惟進行思考,咱們須要思考如何將咱們的應用分爲獨立的,可擴展的以及可測試的部分。
那麼接下來咱們如何採用angularjs思惟去工做呢,如下是一些將其與jQuery對比以後的基本準則:
如下是某個應用的視圖層:
在jQuery中,咱們動態地去修改這個視圖,咱們使用ul定義一個dropdown menu
代碼以下:
<ul class="main-menu">
<li class="active">
<a href="#/home">Home</a>
</li>
<li>
<a href="#/menu1">Menu 1</a>
<ul>
<li><a href="#/sm1">Submenu 1</a></li>
<li><a href="#/sm2">Submenu 2</a></li>
<li><a href="#/sm3">Submenu 3</a></li>
</ul>
</li>
<li>
<a href="#/home">Menu 2</a>
</li>
</ul>
在jQuery中,咱們採用以下邏輯使用這個dropdownMenu
代碼以下:
$('.main-menu').dropdownMenu();
讓咱們回頭看看這個view,你會發現它的功能並非很直白,對於小型應用來說,這樣是能夠的,可是對於大型應用來說,這種方式會讓人費解而且難以維護;
在angularjs中,這個視圖其實是一項基於視圖的功能,咱們能夠這樣來定義ul
<ul class="main-menu" dropdown-menu>
...
</ul>
這兩種方式實際上作了一樣的事情,可是在AngularJS方式下任何人看到這個視圖模板就知道接下來要幹什麼。不管什麼時候當一個新成員加入開發團隊以後他都可以看到這裏並發現這裏有一個叫作dropdownMenu的指令去操做view,他不須要去猜測正確的答案或者審查其餘的代碼,這個視圖就直接告訴咱們它要作什麼,相比於jQuery,它更爲簡潔。
經常有些AngularJS新手問這樣的問題:我怎麼才能找到某個確切類型的全部link並在此基礎上添加一個directive,可是當咱們回答了「你不該該這樣去作,你這是一種半jQuery半angularjs的想法」時,他們會以爲很吃驚。
問題在於他們試圖在AngularJS背景下用jQuery去作某件事,這一般不是一種好的方式,在指令以外你不須要去作任何dom操做,而指令是直接內添加在視圖上的,因此意圖已經很明顯了。記住,不要先設計好以後再去修改,而是先有架構而後在這個框架下再去設計。
數據綁定
這是到目前爲止AngularJS最使人矚目的特性了,在數據綁定方面它捨棄了對DOM的操做方式,而這一切都是由AngularJS來自動更新視圖,你沒必要寫操做dom的代碼,在jQuery中,咱們經常按照如下方式響應事件並修改視圖:
$.ajax({
url: '/myEndpoint.json',
success: function ( data, status ) {
$('ul#log').append('<li>Data Received!</li>');
}
});
相對於這樣一個視圖
<ul class="messages" id="log">
</ul>
除了混雜的問題以外,咱們還存在我以前提到的如何代表本身意圖的問題。可是更爲重要的是,咱們必須人工手動去引用並更新這個DOM節點,若是咱們想刪除其中一條,那麼必須以編程方式去操做那個DOM元素,那麼在這種狀況下咱們怎麼去測試DOM節點以外的邏輯呢,亦或者咱們想改變展現方式呢?
以上代碼顯得凌亂又脆弱,可是在AngularJS中,咱們能夠這樣作:
$http( '/myEndpoint.json' ).then( function ( response ) {
$scope.log.push( { msg: 'Data Received!' } );
});
咱們的視圖應該像下面這樣
<ul class="messages">
<li ng-repeat="entry in log">{{ entry.msg }}</li>
</ul>
在那種狀況下,咱們的視圖也能夠這樣
<div class="messages">
<div class="alert" ng-repeat="entry in log">
{{ entry.msg }}
</div>
</div>
如今咱們不使用ul,而是使用Bootstrap的彈出框,可是咱們不用修改controller中的代碼,更爲重要的是,無論是數據如何修改,視圖層也會自動隨之發生變化,很是簡潔!
儘管我這裏不會作演示,可是你須要知道數據綁定是雙向的,你能夠編輯數據經過添加指令<input ng-model="entry.msg" />,此外還有不少其餘的使人興奮的地方。
區別model層
在jQuery中,DOM相似於一種model,可是在AngularJS中,咱們擁有不一樣於jQuery中的model層以便咱們能夠以任何咱們想要的方式去管理它,它是徹底獨立於視圖以外的。這種方式是有助於咱們進行數據綁定而且能夠保持對分離的關注,並且能夠具有更好的可測試性。
關注點分離
以上所講都和這個整體的話題相關:讓你關注分離,你的視圖層顯示記錄,你的model層表明數據,你還有個服務層用來執行這些可複用的任務。你使用directive來執行dom操做並擴展你的視圖,並將它和controller鏈接起來,這也就是我在其餘方面提到的有關於加強可測試性的緣由。
依賴注入
幫助咱們解決關注點分離的是依賴注入(DI),若是你是一個服務端開發者(Java或者PHP),你可能已經很熟悉這個概念了,可是若是你是從事客戶端開發的,你會以爲這個概念可能有些多餘和純屬追求時髦,可是實際上不是這樣。
從廣義的角度講,DI意味着你能夠自由地聲明組件而後從這些組件中進行實例化,這是理所固然的。你沒必要知道加載順序,文件位置等諸如此類的事情,這種魔力不是可以當即看到,可是我會給出一個例子:測試。
咱們說在應用中,咱們須要一個依賴於應用狀態和本地存儲的服務用來經過一個rest API來執行服務端存儲,當咱們測試咱們的controller時,咱們沒必要和服務端進行通訊,畢竟只是在測試controller而已。咱們僅添加一個與咱們最初組件相同的mock服務,注入器可以確保咱們的controller得到一個虛擬的服務,controller自身沒必要也不須要了解這種差別。
那麼說說測試吧。
4.以測試驅動的開發
這部分是一個架構的第三部分,可是他是很重要的,以致於我須要將它放在最重要的位置。
在咱們全部見過的,用過的以及寫過的jQuery插件中,有多少具備一套測試組件呢?其實並很少,這是由於jQuery在測試上不易控制,可是AngularJS卻與此不一樣。
在jQuery中,測試的惟一方法是使用一個demo頁去建立一個獨立組件來使得咱們的測試能夠執行dom操做。咱們接下來咱們必須開發一個獨立的組件而後將它集成到咱們的應用中來,這是多不方便啊!在不少狀況下,當咱們使用jQuery開發其實是作了不少重複開發而不是以測試驅動的開發,這又能怪咱們嗎?
可是在AngularJS中咱們能夠關注分離點,因此咱們能夠作一些測試驅動的開發。例如,咱們有一個directive用來講明在menu中咱們的當前路徑,咱們能夠在視圖中這樣聲明:
<a href="/hello" when-active>Hello</a>
好了,如今咱們能夠寫一個測試用來測試這個不存在的指令when-active了
it( 'should add "active" when the route changes', inject(function() {
var elm = $compile( '<a href="/hello" when-active>Hello</a>' )( $scope );
$location.path('/not-matching');
expect( elm.hasClass('active') ).toBeFalsey();
$location.path( '/hello' );
expect( elm.hasClass('active') ).toBeTruthy();
}));
咱們直接run測試用例,你會發現是失敗的,這時候須要建立這個指令,以下:
.directive( 'whenActive', function ( $location ) {
return {
scope: true,
link: function ( scope, element, attrs ) {
scope.$on( '$routeChangeSuccess', function () {
if ( $location.path() == element.attr( 'href' ) ) {
element.addClass( 'active' );
}
else {
element.removeClass( 'active' );
}
});
}
};
});
再次run這個測試用例,你會發現經過了而且菜單如請求的樣子顯示,咱們的開發是兼有反覆性和可測試性,很是酷吧!
5.從概念上講,指令不是打包的jQuery
你經常據說,dom操做只能在指令中,這是必須的,你必須嚴肅對待。
讓咱們深刻討論,
某些指令僅僅是裝飾咱們的視圖(例如ngClass),所以有時候直接操做dom是能夠的,可是當一個指令相似於一個小物件而且擁有本身的模板,那麼它應該當作一個分離的關注點,這就是說,它的模板須要和link中的執行邏輯以及其餘controller函數分離開。
AngularJS擁有一整套的工具能夠是這種分離更簡單,使用ngClass指令,咱們能夠動態地更新class,使用ngBind咱們能夠進行雙向數據綁定,使用ngShow和ngHide 咱們
能夠採用編程的形式顯示和隱藏一個元素,也包括咱們本身寫的不少指令。換句話說,咱們能夠不用Dom操做而完成全部工做,dom操做越少,指令越容易測試,越容易指定他們的style屬性,就越容易在未來改變他們,那麼他們就越容易複用和分發。
我看過不少AngularJS新手使用指令封裝一大串 jQuery代碼,換句話說,既然我不能在controller裏面進行dom操做,那麼我能夠將他放在指令中,雖然這相對於直接操做dom好不少,可是任然是錯誤的。
看看咱們在上面的記錄,即便咱們將其放在一個指令中,咱們任然須要以Angular的方式去操做它,這種方式不執行dom操做!在不少時候dom操做是須要的,可是這種狀況比你想的要少得多。當咱們須要作dom操做的時候先問問本身這裏是否必須這樣作,這纔是一種更好的方式。
下面是一個簡單的例子用來代表我經常見到的一種模式,咱們須要I一個可切換的button:
在以上例子中存在如下錯誤:
1.首先,jQuery是沒必要要的,這裏的工做徹底不須要jQuery!
2.第二,即便咱們已經在頁面中引入了jquery,可是咱們沒有理由去使用它,咱們可使用angular.element而咱們的組件也可以運行,即便這個項目中沒有引入jQuery。
3.第三,假設jquery是須要的在咱們的指令中,咱們可使用jqLite去進行替代,只要引入jQuery便可,因此咱們沒必要使用$而是使用angular.element;
4.第四,和第三點聯繫很緊密,jqLite元素沒必要使用$包裹起來,element元素傳遞到link函數中已是一個jQuery對象了;
5.第五,咱們以前已經說過,爲何不將咱們的模板和邏輯混合起來呢?
以上指令能夠按照以下方式來重寫,即便在最複雜的狀況下看起來也如此簡單。
模板元素是在 template屬性中,你能夠很容易替換掉它的style,而邏輯根本不用發生變化,達到了徹底複用!
還有其餘的好處,好比測試起來很簡單,無論模板裏面是什麼,指令API都不會發生改變,因此重構它很簡單。你能夠隨意屢次改變你的模板而不用改變指令,不管你怎麼改變,你的測試總能經過!
因此說指令不是一堆jQuery代碼的集合,好比函數等,而是HTML代碼的擴展,若是HTML代碼不能實現你須要的功能,你能夠寫一個指令去實現它,而後像使用HTML那樣去使用它。
以另一種方式講,AngularJS若是不作額外的事情,想一想咱們怎麼可以使用ngClick,ngClass指令呢?
總結
不要總使用jquery ,甚至不要去引用它,它會阻止你前進,當咱們回到這個問題—你知道你怎麼在AngularJS中以jquery方式解決問題,可是當你使用諸如$等選擇器時,你要想一想它們其實是禁錮了AngularJS,若是你不知道怎麼不用jQuery實現,那麼去請教別人,一次一次去問,最好的方式是不須要使用jQuery,使用jQuery只會致使你的工做量提高。