学习笔记-AngularJs(十)
前面一直在說自定義指令,但是卻一直沒有一次系統地去了解,現在需要我們一起來學習如何去使用自定義指令,去豐富html標簽、屬性,實現多元化、多功能的標簽(或是屬性)。辣么,啥是指令?要了解指令,首先需要了解AngularJs的HTML編譯器,簡單地說讓瀏覽器認識你自定義指令或是Angular的指令集,將其行為運用到DOM上(視圖),分兩個過程編譯和鏈接,編譯階段是遍歷DOM并且收集所有的相關指令,生成一個鏈接函數;鏈接階段是給通過編譯階段調用所說的鏈接函數來將模板與作用域鏈接起來,綁定一個作用域,生成一個動態的視圖。作用域模型的任何改變都會反映到視圖上,并且視圖上的任何用戶操作也都會反映到作用域模型。
那么說到底,由某個屬性、元素名稱、css類名出現而導致的行為,或者說是DOM的變化,能讓你以一種聲明式的方法來擴展HTML表示能力,這就是指令!
官網(忽略,http://t.cn/RUbL4rP)也寫了一個比較詳細的指令demo(具體屬性分析如下):
var myModule = angular.module(...);myModule.directive('directiveName', function factory(injectables) { //工廠函數里面injectables是何意呢?望知道的人告知var directiveDefinitionObject = {priority: 0, //優先級priority,Dom里面會有很多指令,定義優先級,可以使此指令優先執行
terminal:false, //如果被設置為true,那么該指令就會在同一個DOM的指令集和中最后被執行
template: '<div></div>', // or // function(tElement, tAttrs) { ... },// templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... }, //template或templateUrl顧名思義就是模板文件,可以編寫,也可以url,也可以是function(tElement,tAttrs){ return ... ;}
replace: false, //是否替換現在的元素
transclude: false, //重要屬性之一,配合ng-transclude使用,為true時,可以將原元素的內容(html、其他指令)提取到帶有指令ngTransclude的元素內,下面有例子說明!(注:指令的內部可以訪問外部指令的作用域,并且模板也可以訪問外部的作用域對象)
restrict: 'A', //以哪種形式聲明指令行為的格式,有AECM,分別是屬性<div my-directive="exp"> </div> 、元素*<my-directive></my-directive> 、 class*<div class="my-directive: exp;"></div> 、注釋<!-- directive: my-directive exp -->
templateNamespace: 'html', //模板的命名空間,有'html'、'svg'等,默認為'html'
scope: false, //是否創造一個新的作用域(針對指令)
/*scope是最難理解的一個屬性*/
controller: function($scope, $element, $attrs, $transclude, otherInjectables) {...}, //控制器的構造對象,預編譯階段執行,$scope當前作用域,$element當前元素,$attrs當前元素的屬性集合,并且它是共享的,其他指令可以通過它的名字得到(參考依賴屬性(通過require屬性引入)。這就使得指令間可以互相交流來擴大自己的能力。當然也可以是控制 器名字(那么此控制器需要在應用聲明好,這樣便可以通過注入$attrs、$element操縱指令對應模板的dom),$transclude,用來操作嵌入作用域對應的dom,也就是被提取到ngTransclude的元素里面的dom了,下面有例子說明!
controllerAs: 'stringAlias', //定義控制器的別名
require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], // 請求將另一個控制器作為參數傳入到當前鏈接函數。 這個請求需要傳遞被請求指令的控制器的名字。之前有例子關于表單自定義 驗證有使用到,學習筆記-AngularJs(八)
compile: function compile(tElement, tAttrs, transclude) { //tElement指令所在的元素,tAttrs指令所在元素屬性集合return {pre: function preLink(scope, iElement, iAttrs, controller) {...},post: function postLink(scope, iElement, iAttrs, controller) {...}}// or// return function postLink( ... ) { ... } //編譯函數是用來處理需要修改模板DOM(執行于放到dom之前的dom操作)的情況的。因為大部分指令都不需要修改模板,所以這個函數也不常用。返回的是函數或是對象,返回函數時等效于link鏈接函數 },// or// link: { //鏈接函數負責注冊DOM事件和更新DOM。它是在模板被克隆之后執行的。 它也是大部分指令邏輯代碼編寫的地方。scope當前作用域,iElement當前元素,iAttrs當前元素的屬性集合,controller就是上面require屬性的值,于是就可以調用require進來的控制 器的屬性方法,(包括之前講的ngModel或是其他指令controller和controllerAs定義的有控制器名的控制器方法)// pre: function preLink(scope, iElement, iAttrs, controller) { ... }, // post: function postLink(scope, iElement, iAttrs, controller) { ... } // } // or // link: function postLink( ... ) { ... } };return directiveDefinitionObject; });
?compile和link選項是互斥的。如果同時設置了這兩個選項,那么會把compile所返回的函數當作鏈接函數,而link選項本身則會被忽略。
編譯函數負責對模板DOM進行轉換。鏈接函數負責將作用域和DOM進行鏈接。
上面demo有些屬性在實際操作上,都是取默認的屬性,那么官網將其簡化成了這個樣子:
var myModule = angular.module(...);myModule.directive('directiveName', function factory(injectables) { //此處需要注意,在視圖引入指令時,采用的是駱峰命名法,所以調用時應該是directive-namevar directiveDefinitionObject = {link: function postLink(scope, iElement, iAttrs) { ... }};return directiveDefinitionObject;// or// return function postLink(scope, iElement, iAttrs) { ... } }); View Code到這里還是需要編寫些demo,才能起到學習的效果!
在之前的學習筆記-AngularJs(八)里面就有一個自定義表單驗證的demo,情景是這樣的,在input框里面不能寫入“xiaobin”,主要是對ngModel中$setValidity(validationErrorKey, isValid);和$setViewValue(value, trigger);在雙向綁定中是如何實現scope->view、view->scope之間的那個驗證和格式化的學習,沒看過的話,可以去看一下,雖然理解得不透徹!下面貼一下主要代碼:
var custom = angular.module('customControl', ['ngSanitize']);custom.directive("noxiaobin", function () { return { restrict: "A", require: "?ngModel", link: function (scope, element, attrs, ngModel) { if (!ngModel) return; ngModel.$parsers.push(function (v) { //傳說中的驗證器if (v != "xiaobin") { ngModel.$setValidity('noxiaobin', true); //通過獲取從dom過來的值,然后進行驗證,使用$setValidity('noxiaobin', true);改變noxiaobin的值,然后反饋會dom return v; } else { ngModel.$setValidity('noxiaobin', false); return undefined; }}); } } }); View Code在這里,我們另外寫一個比較綜合的例子,dialog.html可到github下載(github地址:https://github.com/xiaobin5201314/AngularJS-Learning/tree/master/block-example/指令-13)
<!doctype html> <html ng-app='directiveModule'><head><meta charset="utf8"/><script src="../jquery.js"></script><script src="../angular.js"></script><script src="../bootstrap.min.js"></script><link rel="stylesheet" href="../bootstrap.min.css"><script>var directive = angular.module('directiveModule', []);//這里是驗證指令的內部可以訪問外部指令的作用域,這樣我們在dialog.html也可以查看到遍歷出來的的arrsdirective.controller("directiveControl",["$scope",function($scope){$scope.arrs=["我是內容一","我是內容二","我是內容三"];$scope.hide=false;}])//將任意可以被注入的ng服務注入到控制器中,便可以在指令中使用它了。控制器中也有一些特殊的服務可以被注入到指令當中,當然這是在應用上聲明、也可以直接寫在controller屬性上directive.controller("directiveChildControl",['$scope','$attrs','$element','$transclude',function($scope,$attrs,$element,$transclude){$element.css('border', '#fff'); //改變模板dom里面的結構$transclude(function (clone) { //這是操作嵌入的作用域里面的domvar a = angular.element('<a>');a.attr('href', 'http://www.cnblogs.com/wuxiaobin');a.text('我的博客原地址');$element.find('.modal-body').append(a);});}])directive.directive("dialog", function () {return {restrict: "AE",replace: true,transclude:true, //配合ng-transclude使用,為true時,可以將原元素的內容(html、其他指令)提取到帶有指令ngTransclude的元素內controller:'directiveChildControl',scope:{title:"@" //模板也可以訪問外部的作用域對象,dialog.html的{{title}}正是局部作用域訪問父作用域的所產生的效果,這樣可以很好實現我們的組件的設計思想,但對于@、=、&的寫法有些不理解,望有更好的學習資料可以提供一下,當然搞懂了,也會更新上來 },templateUrl: 'dialog.html',link: function(scope, element, attrs, ctrl) { console.log(element.html());element.find('.modal-title').css('color', 'red'); }}});</script></head><body ng-controller="directiveControl"> <button class="btn btn-lg btn-primary " data-toggle="modal" data-target="#myModal">彈出模態框</button><dialog title="我是傳遞過來的title"><span ng-repeat="arr in arrs" ng-hide="hide">{{$index}}-{{arr}} <br></span>我的內容即將保存,被提取到<code> span[ng-transclude] </code>上</dialog></body> </html>效果圖:
更多專業前端知識,請上 【猿2048】www.mk2048.com
總結
以上是生活随笔為你收集整理的学习笔记-AngularJs(十)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vue2.0 全家桶开发的网页应用(参照
- 下一篇: 学习笔记-AngularJs(四)