domManip是什麼
dom即Dom元素,Manip是Manipulate的縮寫,連在一起就是Dom操作的意思。
.domManip()是jQuery DOM操作的核心函數
對封裝的節點操作做了參數上的校正支援,與對應處理的調用
append、prepend、before、after、replaceWith
appendTo、prependTo、insertBefore、insertAfter、replaceAll
節點的操作有幾個重點的細節
- 保證最終操作的永遠是dom元素,瀏覽器的最終API只認識那麼幾個介面,所以如果傳遞是字串或者其他的,當然需要轉換
- 針對節點的大量操作,我們肯定是需要引入文檔片段做最佳化的,這個必不可少
我們知道jQuery的的介面是支援多種參數傳遞的,那麼就需要有一個過濾器的中介來處理各種參數類型。
這個任務就交給了domManip,除此之外domManip在設計上需要做的處理:
1:解析參數,字串,函數,對象
2:針對大資料引入文檔片段處理
3:如果參數中包含script的處理
其中還有很多細節的問題:
1:IE下面innerHTML會忽略沒範圍元素,no-scope element(script,link,style,meta,noscript)等,所以這類通過innerHTML建立需要加首碼
2:innerHTML在IE下面會對字串進行trimLeft操作,去掉空白
3: innerHTML不會執行指令碼的代碼,如果支援defer除外
4:很多標籤不能作為div的子項目、td、tr, tbody等等
5:jQuery是合集對象,文檔片段的與事件的複製問題
針對innerHTML不會執行指令碼的代碼,如果支援defer除外的解釋:
div.innerHTML = "<script>alert(aseoe)</srcript>" 這個代碼不會執行
例外的情況:IE9之前滿足幾個條件
1:script設定defer屬性
2: script元素必須位於有範圍元素之後,因為script被認為是無範圍的(頁面中不可見)
換句話說,這樣設定
div.innerHTML = "<div><script defer>alert(1)</srcript></div>" 可以執行
jQuery在內部通過會有一個domManip方法,把這些問題都方方面面處理掉了
綜合上面一系列的問題,jQuery引入了domManip方法
原因清楚了,我們再來看jQuery是如何處理tbody問題,jQuery是相容IE 6瀏覽器的。append、prepend、before和after都是操作Dom元素的函數,如果被插入的對象是table,那就要在table中加入tbody標籤啊
所以domManip,主要是處理這個問題的,他還處理插入元素的順序等等
在結構上首先用extend在原型上拓展了一堆方法,其實每一個的實現都很簡單,重點就是要看懂domManip的使用。可以重點挑兩個方法的實現看一看,不用每個都看。
然後就是appendTo和append之類的處理,大同小異,因為實現差不多,所以就放在一起了
jQuery.fn.extend({ text: function() {}, append: function() {}, prepend: function() {}, before: function() {}, after: function() {}, clone: function() {}, html: function() {}, replaceWith: function() {}, domManip: function() {}, })
其中append方法:
append: function() { return this.domManip(arguments, function(elem) { if (this.nodeType === 1 this.nodeType === 11 this.nodeType === 9) { var target = manipulationTarget(this, elem); target.appendChild(elem); } });}
1:函數調用了domManip函數,傳進去的參數第一個是arguments,這個大家都知道arguments是函數參數對象,是一個類數組對象。這裡arguments可能是包含dom元素的數組,或者html字串
2:第二參數是一個回呼函數,target.appendChild(elem);看到這個代碼就很明了,在回呼函數中分離各自的處理方法,通過domManip抽象出公用的處理,其餘的prepend 、before 、after等介面也是類似的處理
var div = document.querySelectorAll('div')[0];div.innerHTML = "<script>alert('愛思資源網')";這樣JavaScript 不會執行。換句話能插入script標籤,但是不執行指令碼代碼,但是在早起的ie下面,如果設定了defer是另外。如果我們換成jQuery的appned方法:這樣的處理代碼就執行了,可見jQuery的方法內部可不是那麼簡單的處理了$('div').append("<script>alert('愛思資源網')")簡單講,如果.html()傳入的字串有<script> <object> <embedt> <optiont> <style>其中一個 .html()方法就不會用innerHTML 操作,而是用jQuery.append() 處理字串塞入.append()-> .domManip() -> buildFragment() ->clean() 這樣的處理流程clean() 中會動態產生一個div, 將div 的innerHTML 設為傳入的字串,再用getElementsByTagName('script') 的方式把所有的script 抓出來另行儲存clean() 執行完畢回到domManip() 中, domManip() 再將script 們一一拿出來執行如果是外部js 就動態載入,如果是內聯 js 就用eval()
總結下來,domManip主要就做了兩件事:1.根據使用者傳入的參數,建立了多個fragment,然後通過回呼函數參數傳入2.控制script的執行過程,在建立fragment的時候不執行,最後dom操作結束後會統一執行