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


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

以下是我查閱資料時看到的,感覺so詳細,解決了我很多issue,因此copy過來看看

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

創建指令

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

  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元素,將在鼠標移入 時以虛線邊框突出顯示。

指令定義對象

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

指令定義對象的常用屬性如下:

  • template : string

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

  • restrict : string

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

  • 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM