angularjs中展現富文本編輯器文本,向DOM中插入元素

前幾天在用textangular富文本編輯器插件時,將存儲的文本及格式存儲到數據庫中,可是從後臺接口中再向angular頁面插入時卻不能執行,即在Angular中操做DOM沒有實現,後來查看了一下,操做DOM須要使用指令Directive封裝DOM,這樣嘗試以後終於解決了問題,從而對指令也有了很大的瞭解,之後再操做DOm就要當心了html

如下是我查閱資料時看到的,感受so詳細,解決了我不少issue,所以copy過來看看數據庫

原文http://www.cnblogs.com/xuema/p/4350747.htmlapp

建立指令

指令也是一種服務,只是這種服務的定義有幾個特殊要求:編輯器

  1. 必須使用模塊的directive()方法註冊服務
  2. 必須以對象工廠/factory()方法定義服務實現
  3. 對象工廠必須返回一個指令定義對象
  1. //定義指令的類工廠
  2. var directiveFactory = function(injectables){
  3. //指令定義對象
  4. var directiveDefinationObject = {
  5. ...
  6. };
  7. return directiveDefinationObject;
  8. };
  9. //在模塊上註冊指令
  10. angular.module("someModule",[])
  11. .directive("directiveName",directiveFactory);

INSIDE:指令在注入器中的登記名稱是:指令名+Directive。 例如,ng-app指令的服務名稱是:"ngAppDirective"。函數

示例(http://www.dwz.cn/26R4S5中「使用指令封裝DOM操做」第一頁)定義一個簡單的指令ez-hoverable,這個指令被限制只能 出如今屬性的位置,每一個具備這個指令的HTML元素,將在鼠標移入 時以虛線邊框突出顯示。post

指令定義對象

每一個指令定義的工廠函數,須要返回一個指令定義對象。指令定義對象就是 一個具備約定屬性的JavaScript對象,編譯器/$compile在編譯時就根據這 個定義對象對指令進行展開。spa

指令定義對象的經常使用屬性以下:插件

  • template : string

使用template指定的HTML標記替換指令內容(或指令自身)rest

  • restrict : string

用來限定指令在HTML模板中出現的位置。orm

  • replace : true|false

使用這個屬性指明template的替換方式。

  • scope : true|false|{...}

scope屬性爲指令建立私有的做用域,這在建立可複用的Widget時很是有用。

  • link : function(..){...}

link屬性是一個函數,用來在指令中操做DOM樹、實現數據綁定。

  • transclude : true|false|'element'

容許指令包含其餘HTML元素,這一般用於實現一個容器類型的Widget。

template:定義替換模板

最簡單的指令只須要使用template屬性進行模板替換就能夠實現。

template指明一個HTML片斷,能夠用來:

  • 替換指令的內容。這是默認的行爲,可使用replace屬性更改。
  • 若是replace = true,那麼用HTML片斷替換指令自己。
  • 包裹指令的內容,若是transclue屬性爲true。

示例(http://www.dwz.cn/26R4S5中「使用指令封裝DOM操做」第三頁)實現了一個ezCustomer指令,這個指令只是簡單的使用template指定的 模板替換ez-customer的內容:

restrict:限制指令的出現位置

restict屬性能夠是EACM這四個字母的任意組合,用來限定指令的應用場景。 若是不指定這個屬性,默認狀況下,指令將僅容許被用做元素名和屬性名:

  • E - 指令能夠做爲HTML元素使用
  • A - 指令能夠做爲HTML屬性使用
  • C - 指令能夠做爲CSS類使用
  • M - 指令能夠在HTML註釋中使用

咱們對以前的示例,增長一個restrict屬性,限制這個只能做爲元素名使用。 代碼已經預置到右邊,你能夠看到,如今惟一合法的方式是使用以下方式應用指令:

  1. <ez-customer></ez-customer>

考查編譯後的DOM結構,你會發現ez-customer這個」僞「HTML標籤還被保留着,這有時讓完美 主義者有點鬧心:

replace:模板的使用方式

咱們但願使用template完整地替換原始的DOM對象,而不是填充其內容,replace 屬性負責這件事。

replace屬性指明使用template時,如何替換指令元素:

  • true - 編譯時,將使用template替換指令元素
  • false - 編譯時,將使用template替換指令元素的內容

示例(http://www.dwz.cn/26R4S5中「使用指令封裝DOM操做」第五頁)增長了replace屬性,值爲true意味着這個指令要求編譯器使用template 替換原始的DOM元素:

你可能注意到模板的內容稍微修改了一下,這是由於replace爲true時,要求模板有 一個根節點。

做用域問題

默認狀況下,指令沒有本身的scope對象,換句話說,它使用所在DOM對象對應的scope對象。

那麼問題來了,若是一個指令在同一個scope內出現屢次,會怎樣?

  1. <div ng-controller="ezCtrl">
  2. <ez-customer></ez-customer>
  3. <ez-customer></ez-customer>
  4. </div>

沒錯,因爲兩個ez-customer指令都處在ezCtrl開闢的做用域內,因此兩個指令綁定到了一樣的 數據模型上,獲得的是重複的結果。

顯然,咱們能夠將每一個ez-customer指令置於不一樣的做用域下,這意味着咱們給每一個ez-customer 一個不一樣的控制器:

  1. <div ng-controller="ezCtrl1">
  2. <ez-customer></ez-customer>
  3. </div>
  4. <div ng-controller="ezCtrl2">
  5. <ez-customer></ez-customer>
  6. </div>

看起來很怪異,對嗎?

scope:使用隔離的做用域

經過設置scope屬性,指令的每一個實例都將得到一個隔離的本地做用域:

  1. var ezCustomerDirectiveFactory = function(){
  2. return {
  3. restrict:"E",
  4. replace:true,
  5. scope:{
  6. name : "@name",
  7. address : "=address"
  8. },
  9. template:"<div>name:{{name}} address:{{address}}</div>"
  10. }
  11. }

在上面的例子中,咱們在本地scope上定義了兩個屬性:name和address,這樣在 模板中就可使用name和address了。

你應該已經注意到,name屬性的值以前有一個@符號,這是一個約定好的標記,它 告訴編譯器,本地scope上的name值須要從應用這個指令的DOM元素的name屬性值 讀取,若是DOM元素的name屬性值變了,那麼本地scope上的name值也會變化。

一樣,address屬性以前的=符號也是一個約定好的標記,它告訴編譯器,本地scope 上的address屬性值和DOM元素的address屬性值指定的外部scope對象上的模型須要 創建雙向鏈接:外部scope上模型的變化會改變本地scope上的address屬性,本地 scope上address屬性的變化也會改變外部scope上模型的變化。

有點繞,上個圖:

從圖中能夠看出:

  1. 指令的template綁定的是本地scope上的name和address。
  2. 本地scope的name屬性的值始終是ez-customer對象上name屬性的值
  3. 本地scope的address屬性值始終和ez-customer對應的scope對象上的Emmy.address 保持同步。

link:在指令中操做DOM

若是須要在指令中操做DOM,咱們須要在對象中定義link屬性,link函數的定義以下:

  1. function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }

注意link函數的參數,AngularJS在編譯時負責傳入正確的值:

  • scope

指令對應的scope對象。若是指令沒有定義本身的本地做用域,那麼傳入的就是外部的 做用域對象。

  • iElement

指令所在DOM對象的jqLite封裝。若是使用了template屬性,那麼iElement對應 變換後的DOM對象的jqLite封裝。

  • iAttrs

指令所在DOM對象的屬性集。這是一個Hash對象,每一個鍵是駝峯規範化後 的屬性名。

後兩個參數咱們先略過。

示例

示例(http://www.dwz.cn/26R4S5中「使用指令封裝DOM操做」第八頁)中,咱們實現了一個能夠指定顯示格式的小時鐘指令:ezCurrentTime。和原來同樣, 咱們在link函數中啓動定時器,並在定時器中更新DOM。有幾點解釋下:

  1. 咱們在scope上使用$watch()方法對format的值進行監聽,並使用這個值調整顯示格式
  2. 咱們監聽element的$destroy事件,這個事件是在DOM對象銷燬時觸發。咱們在這個事件觸發時 銷燬定時器以釋放資源
  3. 咱們使用了AngularJS內置的$interval服務,而不是setInterval()函數建立定時器。
  4. 咱們使用了AngularJS內置的dateFilter過濾器服務,對時間的顯示進行格式化。 和$interval同樣,dateFilter服務也是經過注入器注入的。

transclude:包含其餘元素

有些指令須要可以包含其餘未知的元素。好比咱們定義一個指令ez-dialog,用來 封裝對話框的樣式和行爲,它應當容許在使用期(也就是在界面模板文件裏)才指 定其內容:

  1. <ez-dialog>
  2. <p>對話框的內容在咱們開發ez-dialog指令的時候是沒法預計的。這部份內容須要
  3. 被轉移到展開的DOM樹中適當的位置。</p>
  4. </ez-dialog>

transclude屬性能夠告訴編譯器,利用所在DOM元素的內容,替換template中包含 ng-transclude指令的元素的內容:

從上圖中能夠看到,使用transclude有兩個要點:

  1. 須要首先聲明transclude屬性值爲true,這將告訴編譯器,使用咱們這個指令的 DOM元素,其內容須要被複制並插入到編譯後的DOM樹的某個點。
  2. 須要在template屬性值中使用ng-transclude指明插入點。

右邊嵌入了ez-dialog的實現實例(http://www.dwz.cn/26R4S5中「使用指令封裝DOM操做」第九頁)。

參考資料:http://www.dwz.cn/26R4S5

相關文章
相關標籤/搜索