AngularJS封裝指令方法詳解_AngularJS

來源:互聯網
上載者:User

本文執行個體講述了AngularJS封裝指令方法。分享給大家供大家參考,具體如下:

引言:angularjs是一個中等重量級的前端開發架構

HTML是一門很好的為靜態文本設計的語言,但要構建動態web應用它就顯的乏力了。通常,我們使用以下技術來解決靜態網頁技術在構建Live App上的不足:

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的事件綁定機制。既然Crowdsourced Security Testing們都在用,我們又何苦不用?組件化的思想沒有錯,但沒必要因此把自己的手腳綁住。唯一要注意的問題是,不要用jquery的代碼破壞了angularjs的結構。對此我的原則如下,不足之處還請指出:

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

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

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

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

看起來很簡單,但是你如果真的使用了這個指令,你就會發現它根本不起效果。在仔細查看文檔後,我才發現這實際是Crowdsourced Security Testing們使用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代碼的出現。

更多關於AngularJS相關內容感興趣的讀者可查看本站專題:《AngularJS入門與進階教程》及《AngularJS MVC架構總結》

希望本文所述對大家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.