AngularJS 自定義控件

AngularJS Custom Directives

好討厭不帶日期的博客,而且說得好啰嗦

自定義指令介紹

AngularJS 指令作用是在 AngulaJS 應用中操作 Html 渲染。比如說,內插指令 ( {{ }} ), ng-repeat 指令以及 ng-if 指令。

當然你也可以實現自己的。這就是 AngularJS 所謂的"教會 HTML 玩新姿勢"。本文將告訴你如何做到。

指令類型

可以自定義的指令類型如下:

  • 元素
  • 屬性
  • CSS class
  • Comment directives

這里面,AngularJS 強烈建議你用元素和屬性類型,而不用 CSS class 和 comment directives (除非迫不得已)。

指令類型決定了指令何時被激活。當 AngularJS 在 HTML 模板中找到一個 HTML 元素的時候,元素指令被激活。當 AngularJS 找到一個 HTML 元素屬性時,屬性指令被激活。當 AngularJS 找到一個 CSS class 時, CSS class 指令被激活,最后,當 AngularJS 找到 HTML comment 時,comment directive 被激活。

基礎例子

你可以向模塊注冊一個指令,像這樣:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = "My first directive: {{textToInsert}}";return directive;
});

來看模塊中調用的 directive() 函數。當你調用該函數時,意味著你要注冊一個新指令。directive() 函數的第一個參數是新注冊指令的名稱。這是之后你在 HTML 模板中調用它的時候用的名稱。例子中,我用了 'div' ,意思是說當 HTML 模板每次在找到 HTML 元素類型是 div 的時候,這個指令都會被激活。

傳遞給 directive 函數的第二個參數是一個工廠函數。調用該函數會返回一個指令的定義。 AngularJS 通過調用該函數來獲取包含指令定義的 Javascript 對象。如果你有仔細看上面的例子,你會知道它返回的確是是一個 Javascript 對象。

這個從工廠函數中返回的 Javascript 對象有兩個屬性: restrict 和 template 字段。

restrict 字段用來設置指令何時被激活,是匹配到 HTML 元素時,還是匹配到元素屬性時。也就是指令類型。把restrict 設置為 E 時,只有名為 div 的 HTML 元素才會激活該指令。把 restrict 設置為 A 時,只有名為 div 的 HTML 元素屬性才會激活該指令。你也可以用 AE ,這樣會使得匹配到元素名和元素屬性名時,都可以激活該指令。

template 字段是一個 HTML 模板,用來替換匹配的 div 元素。它會把匹配到的 div 當成一個占位符,然后用 HTML 模板在同一位置來替換掉它。也就是說,HTML 模板替換匹配的到 HTML 元素。

比如說你的 HTML 頁面有這樣一段 HTML:

<!-- lang: js -->
<div ng-controller="MyController" ><div>This div will be replaced</div>
</div>

當 AngularJS 找到內嵌的 div 的時候,會激活自定義的指令。然后把該 div 元素替換掉,替換后的 HTML 將變成這樣:

<!-- lang: js -->
My first directive: {{textToInsert}}

然后你看到了,這段 HTML 里面包含了一個內插指令 ({{textToInsert}})。AngularJS 會再執行一次,讓內插指令實際值顯示出來。然后 $scope.textToInsert 屬性將會在這個 HTML 點上替換掉內插指令占位符。

template 和 templateUrl 屬性

創建自定義指令最簡單的例子就是上面這樣了。你的指令用來生成 HTML,然后你把 HTML 放到指令定義對象的 template 屬性中。下面這個例子是上面那最簡單的例子的重復,注意 template 部分:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.template = "My first directive: {{textToInsert}}";return directive;
});

如果 HTML 模板越來越大,把它寫在一個 Javascript 字符串中肯定非常難維護。你可以把它放到一個單獨的文件中,然后 AngularJS 可以通過這個文件把它加載進來。然后再把 HTML 模板文件的 URL 放到指令定義對象的 templateUrl 屬性中。下面是例子:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('div', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = "/myapp/html-templates/div-template.html";return directive;
});

然后 AngularJS 會從 templateUrl 屬性中設置的 URL 將 HTML 模板加載進來。

用獨立的 HTML 模板文件,設置 templateUrl 屬性,在你要創建更多的通用指令時會顯得更加有用,比如說用來顯示用戶信息的指令。例子:

<!-- lang: js -->
myapp = angular.module("myapp", []);myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.templateUrl = "/myapp/html-templates/userinfo-template.html";return directive;
});

例子創建了一個指令,當AngularJS 找到一個 元素的時候就會激活它。AngularJS 加載指向 /myapp/html-templates/userinfo-template.html 的模板并解析它,它就像從一開始就被嵌在上一級 HTML 文件中一樣。

從指令中隔離 $scope

在上面的例子中,把 userinfo 指令硬綁定到了 $scope ,因為 HTML 模板是直接引用 textToInsert 屬性的。直接引用 $scope 讓指令在同一個 controller 中的時候,非常難復用,因為 $scope 在同一個 controller 中的值都是一樣的。比如說,你在頁面的 HTML 中這樣寫的時候:

<!-- lang: js -->
<userinfo></userinfo>
<userinfo></userinfo>

這兩個 元素會被同樣的 HTML 模板取代,然后綁定到同樣的 $scope 變量上。結果就是兩個 元素將會被一模一樣的 HTML 代碼給替換了。

為了把兩個 元素綁定到 $scope 中的不同的值,你需要給 HTML 模板一個 isolate scope。

所謂 isolate scope 是綁定在指令上的獨立的 scope 對象。下面是定義的例子:

<!-- lang: js -->
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E';directive.template = "User : {{user.firstName}} {{user.lastName}}";directive.scope = {user : "=user"}return directive;
})

請看 HTMl 模板中的兩個內插指令 {{user.firstName}} 和 {{user.lastName}}。注意 user. 部分。以及directive.scope 屬性。 directive.scope 是個帶 user 屬性的 Javascript 對象。于是 directive.scope 就成為了 isolate scope 對象,現在 HTML 模板被綁到了 directive.scope.user 上(通過 {{user.firstName}} 和 {{user.lastName}} 內插指令)。

directive.scope.user 被設置為 "=user" 。意思是說 directive.scope.user 和 scope 中的屬性綁在一起的(不是 isolate scope),scope 中的屬性通過 user 屬性傳入 元素。聽起來挺費勁的,直接看例子:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo>

這兩個 元素都有 user 屬性。user 的值指向了 $scope 中同名屬性,被指定的 $scope 中的屬性將在 userinfo 的 isolate scope object 中被使用。

下面是完整的例子:

<!-- lang: js -->
<userinfo user="jakob"></userinfo>
<userinfo user="john"></userinfo><script>
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E';directive.template = "User : <b>{{user.firstName}}</b> <b>{{user.lastName}}</b>";directive.scope = {user : "=user"}return directive;
});myapp.controller("MyController", function($scope, $http) {$scope.jakob = {};$scope.jakob.firstName = "Jakob";$scope.jakob.lastName  = "Jenkov";$scope.john = {};$scope.john.firstName = "John";$scope.john.lastName  = "Doe";
});</script>

compile() 和 link() 函數

如果你需要在你的指令中做更高級的操作,單純使用 HTML 模板做不到的時候,你可以考慮使用 compile() 和 link() 函數。

compile() 和 link() 函數定義了指令如何修改匹配到的 HTML。

當指令第一次被 AngularJS 編譯的時候 (在 HTML 中第一次被發現),compile() 函數被調用。compile() 函數將為該元素做一次性配置。

然后 compile() 函數以返回 link() 作為終結。link() 函數將在每次元素被綁到 $scope 數據時,都被調用。

下面是例子:

<!-- lang: js -->
<script>
myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.compile = function(element, attributes) {// do one-time configuration of element.var linkFunction = function($scope, element, atttributes) {// bind element to data in $scope}return linkFunction;}return direc
t```  
ive;
});    
</script>    
**compile() 函數帶兩個參數: element 和 attributes。**element 參數是 jqLite 包裝過的 DOM 元素。AngularJS 有一個簡化版 jQuery 可以用于操作 DOM,所以對 element 的 DOM 操作方式和你在 jQuery 中所知的一樣。attributes 參數是包含了 DOM 元素中的所有的屬性集合的 Javascript 對象。因此,你要訪問某個屬性你可以這樣寫 attributes.type。link() 函數帶三個參數: $scope,element 和 attributes。element 和attributes 參數和傳到 compile() 函數中的一樣。$scope 參數是正常的 scope 對象,或者當你在指令定義對象中定義了 isolate scope 的時候,它就是 isolate scope。compile() 和 link() 的命名相當混亂。它們肯定是受編譯隊伍的啟發而命名的。我可以看到相似點,不過一個編譯器是傳入一次,然后輸出。而指令則是配置一次 HTML 元素,然后在之后的 $scope 對象改變時進行更新。compile() 函數如果叫做 create(), init() 或者 configure()也許會更好。這樣可以表達出這個函數只會被調用一次的意思。而 link() 函數如果叫 bind() 或者 render() 也許會更好,能更好的表達出這樣的意思,在指令綁定數據或者重綁定數據的時候,這個函數將會被調用。下面是一個完整的例子,演示了指令使用 compile() 和 link() 函數的:


<userinfo >This will be replaced</userinfo>

myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.compile = function(element, attributes) {element.css("border", "1px solid #cccccc");var linkFunction = function($scope, element, attributes) {element.html("This is the new content: " + $scope.firstName);element.css("background-color", "#ffff00");}return linkFunction;}return directive;
})
myapp.controller("MyController", function($scope, $http) {$scope.cssClass = "notificationDiv";$scope.firstName = "Jakob";$scope.doClick = function() {console.log("doClick() called");}
});


compile() 函數設置 HTML 元素的 border 。它只執行一次,因為 compile() 函數只執行一次。**link() 替換 HTML 元素內容,并且把背景顏色設置為黃色。**把設置 border 放在 compile(), 把背景顏色放在 link() 沒啥特別的理由。你可以把所有的操作都丟到 compile(),或者都放到 link()。如果都放到 compile() 它們只會被設置一次(你需要它們是常量的話)。如果放到了 link(),它們會在每次 HTML 元素被綁到 $scope 的時候都發生變化。當你希望根據 $scope 中的數據來設置 boarder 和背景顏色的時候這非常有用。**只設置 link() 函數**有時候你的指令可能不需要 compile() 。你只需要用到 link()。這種情況下,你可以直接設置指令定義對象中的 link() 函數。下面是一個對上面例子的修改,只用 link 函數:


<userinfo >This will be replaced</userinfo>

myapp = angular.module("myapp", []);
myapp.directive('userinfo', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.link = function($scope, element, attributes) {element.html("This is the new content: " + $scope.firstName);element.css("background-color", "#ffff00");}return directive;
})
myapp.controller("MyController", function($scope, $http) {$scope.cssClass = "notificationDiv";$scope.firstName = "Jakob";$scope.doClick = function() {console.log("doClick() called");}
});

注意 link() 方法和之前例子中返回的 link() 是完全一樣的。**通過 Transclusion 封裝元素的指令**到目前為止,我們看到的所有例子,都是把匹配到的元素內容給替換為指令的指定內容,不管是通過 Javascript 也好或者 HTML 模板也好。不過如果遇到內容中有部分是開發者可以指定的內容的時候呢?比如說:


This is a transcluded directive {{firstName}}

標記為 <mytransclude> 的元素,它的部分內容可以由開發者設置。因此,這部分 HTML 不應該被指令的 HTML 模板給替換。我們實際上是希望這部分 HTML 由 AngularJS 來處理的。這個處理叫做 "transclusion"。 1為了能讓 AngularJS 把這部分 HTML 放到指令內部處理,你必須設置指令定義對象的 transclude 屬性為 true。你還需要告訴 AngularJS,指令的 HTML 模板中哪一部分需要把 transcluded HTML 包含進來。你可以通過插入 ng-transclude 屬性 (實際上,是一個指令) 到 HTML 模板的 HTML 元素中,標記你想要添加 transcluded HTML 的元素。下面是一個 AngularJS 指令,演示如何使用 transclusion:


This is a transcluded directive {{firstName}}

myapp = angular.module("myapp", []);
myapp.directive('mytransclude', function() {var directive = {};directive.restrict = 'E'; /* restrict this directive to elements */directive.transclude = true;directive.template = "<div class='myTransclude' ng-transclude></div>";return directive;
});
myapp.controller("MyController", function($scope, $http) {$scope.firstName = "Jakob";
});

注意 <mytransclude> 元素內的 HTML。這部分 HTML 代碼包含了內插指令 {{firstName}}。我們希望 AngularJS 來為我們處理這部分 HTML,讓內插指令執行。為了實現這個目的,我在指令定義對象中把 transclude 設置為 true。我還在 HTML 模板中用到了 ng-transclude 屬性。這個屬性告訴 AngularJS 什么元素需要插入到 transcluded HTML。1: 說實話,我沒看懂那個定義,說的太TM難懂了,而且我好不爽寫代碼沒輸出的教程。只好自己動手做做例子。我覺得其實應該是這樣的,把目標元素內容作為一個整體,拿到 HTML 模板中來,添加到 ng-transclude 指定的標簽下。這個處理,我覺得應該就是叫做 transcluded。比如說剛才的例子(有些 bug,自己修正一下),因為 directive.transclude = true; ,所以原來 <mytransclude> 元素內的 HTML:


This is a transcluded directive {{firstName}}

在激活指令 'mytransclude' 的時候,會被拿到 'mytransclude' 指令的模板中來,放到被 ng-transclude 指定的


"

"
中。于是最終輸出的結果應該是:


<div class='myTransclude' ng-transclude><span class="ng-scope ng-binding">This is a transcluded directive Jakob</span>
</div>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/395575.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/395575.shtml
英文地址,請注明出處:http://en.pswp.cn/news/395575.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

oracle 監聽加密 tcps,通過oracle wallet配置listener tcps加密

一 配置客戶端和服務端的wallet2端配置方法一致&#xff0c;相互添加證書orapki wallet create -wallet "/u01/oracle/wallet" -pwd Wdkf984jkkgekj434FKFD -auto_login_localorapki wallet add -wallet "/u01/oracle/wallet" -pwd Wdkf984jkkgekj434FKFD …

[財務知識] debt debit credit 的區別于聯系

https://blog.csdn.net/sjpljr/article/details/70169303 劍橋詞典解釋分別為&#xff1a; Debt [C or U ] n.something, especially money, which is owed to someone else, or the state of owing something借款&#xff0c;欠款&#xff1b;債務He ran/got into debt ( borr…

SpringMVC視圖解析器

SpringMVC視圖解析器 前言 在前一篇博客中講了SpringMVC的Controller控制器&#xff0c;在這篇博客中將接著介紹一下SpringMVC視 圖解析器。當我們對SpringMVC控制的資源發起請求時&#xff0c;這些請求都會被SpringMVC的DispatcherServlet處理&#xff0c;接著 Spring會分析看…

TIOBE 10月編程語言排行榜 : GO 問鼎本年度語言 ?

距離2016年度編程語言的公布只剩3個月了&#xff0c;誰將奪得桂冠&#xff1f; 與去年同期相比&#xff0c;2016年只有Go語言和Groovy語言的增長率超過了1%。 需要注意的是&#xff0c;Groovy語言2015年以一個爆炸性增長的收尾&#xff0c;所以到2017年1月左右的增長速度可能不…

校友郵箱_freeCodeCamp校友網絡:FCC校友的自主指導網絡

校友郵箱by peterWeinberg彼得溫伯格 freeCodeCamp校友網絡&#xff1a;FCC校友的自主指導網絡 (The freeCodeCamp Alumni Network: A homegrown mentorship network for FCC alumni) For the last year, I’ve been spending nearly all my free time learning to code. I’v…

oracle severity,ORACLE10G如何清除OEM下的歷史警告信息

ORACLE10G如何清除OEM下的歷史警告信息問題描述&#xff1a;OEM的HOME頁面可以顯示ORACLE的報警信息&#xff0c;但報警事件清除后該信息不會自動清除。隨著時間的增長&#xff0c;信息量逐漸加大&#xff0c;解決方法是手工予以清除。SampleCluster DatabaseTablespaces FullT…

使用 ReSharper,輸入即遵循 StyleCop 的代碼格式化規范

StyleCop 可以幫助強制執行代碼格式化規范&#xff0c;ReSharper 可以幫助你更高效地編寫代碼。把兩者結合起來&#xff0c;你便能高效地編寫符合團隊強制格式化規范的代碼來。 本文就介紹如何使用 ReSharper 來高效地遵循 StyleCop 的代碼格式化規范。 本文內容 安裝插件 Styl…

Oracle數據庫備份恢復,巡檢須要關注的對象設置以及相關恢復概述

數據庫備份恢復。巡檢須要關注的對象設置&#xff1a; 1.數據庫名稱&#xff0c;以及DBID&#xff1b; --dbid在v$database中 SYSORCL>select dbid,name from v$database; DBID NAME ---------- --------- 1385095721 ORCL 2.控制文件的位置&#xff1b; s…

Python迭代器

一、文件迭代器 readline&#xff08;&#xff09;每次讀取文件的一行&#xff0c;每次調用readline方法會自動到下一行&#xff0c;到文件末尾時&#xff0c;會返回空字符串。 _next_()方法同readline&#xff08;&#xff09;一樣&#xff0c;只是到最后一行會引發stopiterat…

成千上萬的在線課程時,如何保持理智和學習編碼

by Travis Chan通過特拉維斯陳 成千上萬的在線課程時&#xff0c;如何保持理智和學習編碼 (How to stay sane and learn to code when there are thousands of online courses) We live in the information age. Information about anything we can think of is accessible to…

oracle中noguarantee,聊聊UNDO_RETENTION作用(修改guarantee)

oracle10g中&#xff0c;針對dba_tablespace&#xff0c;加了其中一個額外列是retention.回憶一下Oracle 10g之前,在自動Undo管理的模式下&#xff0c;我們都知道undo_retention參數的作用是用來控制當transaction被commit之后&#xff0c;undo信息的保留時間。這些undo信息可以…

【Hankson 的趣味題】

可能我只適合這道題的50分 但還是要爭取一下的 我們知道對于\(gcd\)和\(lcm\)有這樣的定義 \(a\prod _{i1}^{\pi(a)}p_i^{d_{i}}\) \(b\prod _{i1}^{\pi(b)}p_i^{g_{i}}\) 那么則有 \(gcd(a,b)\prod_{i1}^{\pi(max(a,b))} p_i^{min(g_i,d_i)}\) \(lcm(a,b)\prod_{i1}^{\pi(max(…

C# 控件雙緩沖控制 ControlStyles 枚舉詳解

ControlStyles 枚舉.NET Framework 4指定控件的樣式和行為。 此枚舉有一個 FlagsAttribute 特性&#xff0c;通過該特性可使其成員值按位組合。 命名空間&#xff1a; System.Windows.Forms程序集&#xff1a; System.Windows.Forms&#xff08;在 System.Windows.Forms.dll …

協作機器人 ai算法_如果我們希望人工智能為我們服務而不是不利于我們,我們需要協作設計...

協作機器人 ai算法by Mariya Yao姚iya(Mariya Yao) 如果我們希望人工智能為我們服務而不是不利于我們&#xff0c;我們需要協作設計 (If we want AI to work for us — not against us — we need collaborative design) The trope “there’s an app for that” is becoming …

Shadow Brokers 公布 2.1 萬美元的 0day 訂閱服務

神秘黑客組織 Shadow Brokers 宣布將向支付 2.1 萬美元 0day 訂閱服務的個人公布最新一批的 NSA 工具&#xff0c;這一聲明給全世界的白帽子黑客或安全研究人員造成了一場倫理危機。 一方面&#xff0c;Shadow Brokers 此前釋出過創造出勒索軟件 WannaCry 的 NSA 工具&#xff…

linux awk 常見字符串處理

awk指定輸出列&#xff1a; awk {print $0} file #打印所有列awk {print $1} file #打印第一列 awk {print $1, $3} file #打印第一和第三列 cat file | awk {print $3, $1} #打印第三列和第一列&#xff0c;注意先后順序。 cat file | awk {print $3, $NF} #打印第三列…

oracle ldap 配置,ldap 安裝

一、安裝步驟1:配置yum源掛著盤鏡像時用到&#xff1a; 這里不做解釋;(yum clean all && yum makecache)2:安裝OpenLDAP組件1)安裝OpenLDAP組件命令如下:[rootgitea ~]# yum install openldap openldap-servers openldap-clients openldap-devel compat-openldap -ycom…

scp跨主機拷貝工具

參考&#xff1a;http://www.cnblogs.com/hitwtx/archive/2011/11/16/2251254.html SSH上A機&#xff0c;要將10.1.17.95機/tpdata/shell_script/下面的crontab.tar.gz文件拷貝到A機的當前文件夾下面&#xff1a; scp weblogic10.1.17.95:/tpdata/shell_script/crontab.tar.gz …

Google Chrome瀏覽器可能在您不知情的情況下破壞了您的測試

by Robert Axelsen羅伯特阿克森(Robert Axelsen) Google Chrome瀏覽器可能在您不知情的情況下破壞了您的測試 (Google Chrome might have broken your tests without you even knowing about it) My colleague just discovered that Chrome 58 (released April 19th) has sile…

Java 9 將采用新的版本字符串格式

在現有的版本編碼格式使用了兩年之后&#xff0c;從Java 9開始&#xff0c;Java版本方案將根據業內軟件版本編碼的最佳實踐進行修改。使用或解析Java版本字符串的應用程序開發人員要注意了&#xff0c;因為這種變化可以會影響他們的應用程序。 正如JEP 223所闡述的那樣&#xf…