国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

讀 Zepto 源碼之操作 DOM

beita / 2631人閱讀

摘要:輔助方法這個方法遞歸遍歷的子節點,將節點交由回調函數處理。對集合進行遍歷,調用方法,如果為函數,則將回調函數返回的結果作為參數傳給否則,如果為,則將也即包裹元素的副本傳給,否則直接將傳給。

這篇依然是跟 dom 相關的方法,側重點是操作 dom 的方法。

讀Zepto源碼系列文章已經放到了github上,歡迎star: reading-zepto

源碼版本

本文閱讀的源碼為 zepto1.2.0

.remove()
remove: function() {
  return this.each(function() {
    if (this.parentNode != null)
      this.parentNode.removeChild(this)
    })
},

刪除當前集合中的元素。

如果父節點存在時,則用父節點的 removeChild 方法來刪掉當前的元素。

相似方法生成器

zeptoafterprependbeforeappendinsertAfterinsertBeforeappendToprependTo 都是通過這個相似方法生成器生成的。

定義容器
adjacencyOperators = ["after", "prepend", "before", "append"]

首先,定義了一個相似操作的數組,注意數組里面只有 afterprependbeforeappend 這幾個方法名,后面會看到,在生成這幾個方法后,insertAfterinsertBeforeappendToprependTo 會分別調用前面生成的幾個方法。

輔助方法traverseNode
function traverseNode(node, fun) {
  fun(node)
  for (var i = 0, len = node.childNodes.length; i < len; i++)
    traverseNode(node.childNodes[i], fun)
}

這個方法遞歸遍歷 node 的子節點,將節點交由回調函數 fun 處理。這個輔助方法在后面會用到。

核心源碼
adjacencyOperators.forEach(function(operator, operatorIndex) {
  var inside = operatorIndex % 2 //=> prepend, append

  $.fn[operator] = function() {
    // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
    var argType, nodes = $.map(arguments, function(arg) {
      var arr = []
      argType = type(arg)
      if (argType == "array") {
        arg.forEach(function(el) {
          if (el.nodeType !== undefined) return arr.push(el)
          else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())
          arr = arr.concat(zepto.fragment(el))
        })
        return arr
      }
      return argType == "object" || arg == null ?
        arg : zepto.fragment(arg)
    }),
        parent, copyByClone = this.length > 1
    if (nodes.length < 1) return this

    return this.each(function(_, target) {
      parent = inside ? target : target.parentNode

      // convert all methods to a "before" operation
      target = operatorIndex == 0 ? target.nextSibling :
      operatorIndex == 1 ? target.firstChild :
      operatorIndex == 2 ? target :
      null

      var parentInDocument = $.contains(document.documentElement, parent)

      nodes.forEach(function(node) {
        if (copyByClone) node = node.cloneNode(true)
        else if (!parent) return $(node).remove()

        parent.insertBefore(node, target)
        if (parentInDocument) traverseNode(node, function(el) {
          if (el.nodeName != null && el.nodeName.toUpperCase() === "SCRIPT" &&
              (!el.type || el.type === "text/javascript") && !el.src) {
            var target = el.ownerDocument ? el.ownerDocument.defaultView : window
            target["eval"].call(target, el.innerHTML)
          }
        })
          })
    })
  }
調用方式

在分析之前,先看看這幾個方法的用法:

after(content)
prepend(content)
before(content)
append(content)

參數 content 可以為 html 字符串,dom 節點,或者節點組成的數組。after 是在每個集合元素后插入 contentbefore 正好相反,在每個集合元素前插入 contentprepend 是在每個集合元素的初始位置插入 contentappend 是在每個集合元素的末尾插入 contentbeforeafter 插入的 content 在元素的外部,而 prependappend 插入的 content 在元素的內部,這是需要注意的。

將參數 content 轉換成 node 節點數組
var inside = operatorIndex % 2 //=> prepend, append

遍歷 adjacencyOperators,得到對應的方法名 operator 和方法名在數組中的索引 operatorIndex

定義了一個 inside 變量,當 operatorIndex 為偶數時,inside 的值為 true,也就是 operator 的值為 prependappend 時,inside 的值為 true 。這個可以用來區分 content 是插入到元素內部還是外部的方法。

$.fn[operator] 即為 $.fn 對象設置對應的屬性值(方法名)。

var argType, nodes = $.map(arguments, function(arg) {
  var arr = []
  argType = type(arg)
  if (argType == "array") {
    arg.forEach(function(el) {
      if (el.nodeType !== undefined) return arr.push(el)
      else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())
      arr = arr.concat(zepto.fragment(el))
    })
    return arr
  }
  return argType == "object" || arg == null ?
    arg : zepto.fragment(arg)
}),

變量 argType 用來保存變量變量的類型,也即 content 的類型。nodes 是根據 content 轉換后的 node 節點數組。

這里用了 $.map arguments 的方式來獲取參數 content ,這里只有一個參數,這什么不用 arguments[0] 來獲取呢?這是因為 $.map 可以將數組進行展平,具體的實現看這里《讀zepto源碼之工具函數》。

首先用內部函數 type 來獲取參數的類型,關于 type 的實現,在《讀Zepto源碼之內部方法》 已經作過分析。

如果參數 content ,也即 arg 的類型為數組時,遍歷 arg ,如果數組中的元素存在 nodeType 屬性,則斷定為 node 節點,就將其 push 進容器 arr 中;如果數組中的元素為 zepto 對象(用 $.zepto.isZ 判斷,該方法已經在《讀Zepto源碼之神奇的$》有過分析),不傳參調用 get 方法,返回的是一個數組,然后調用數組的 concat 方法合并數組,get 方法在《讀Zepto源碼之集合操作》有過分析;否則,為 html 字符串,調用 zepto.fragment 處理,并將返回的數組合并,`zepto.fragment 在《讀Zepto源碼之神奇的$》中有過分析。

如果參數類型為 object (即為 zepto 對象)或者 null ,則直接返回。

否則為 html 字符串,調用 zepto.fragment 處理。

parent, copyByClone = this.length > 1
if (nodes.length < 1) return this

這里還定義了 parent 變量,用來保存 content 插入的父節點;當集合中元素的數量大于 1 時,變量 copyByClone 的值為 true ,這個變量的作用后面再說。

如果 nodes 的數量比 1 小,也即需要插入的節點為空時,不再作后續的處理,返回 this ,以便可以進行鏈式操作。

insertBefore 來模擬所有操作
return this.each(function(_, target) {
  parent = inside ? target : target.parentNode

  // convert all methods to a "before" operation
  target = operatorIndex == 0 ? target.nextSibling :
  operatorIndex == 1 ? target.firstChild :
  operatorIndex == 2 ? target :
  null

  var parentInDocument = $.contains(document.documentElement, parent)
  ...
})

對集合進行 each 遍歷

parent = inside ? target : target.parentNode

如果 node 節點需要插入目標元素 target 的內部,則 parent 設置為目標元素 target,否則設置為當前元素的父元素。

target = operatorIndex == 0 ? target.nextSibling :
  operatorIndex == 1 ? target.firstChild :
  operatorIndex == 2 ? target :
  null

這段是將所有的操作都用 dom 原生方法 insertBefore 來模擬。 如果 operatorIndex == 0 即為 after 時,node 節點應該插入到目標元素 target 的后面,即 target 的下一個兄弟元素的前面;當 operatorIndex == 1 即為 prepend 時,node 節點應該插入到目標元素的開頭,即 target 的第一個子元素的前面;當 operatorIndex == 2 即為 before 時,insertBefore 剛好與之對應,即為元素本身。當 insertBefore 的第二個參數為 null 時,insertBefore 會將 node 插入到子節點的末尾,剛好與 append 對應。具體見文檔:Node.insertBefore()

var parentInDocument = $.contains(document.documentElement, parent)

調用 $.contains 方法,檢測父節點 parent 是否在 document 中。$.contains 方法在《讀zepto源碼之工具函數》中已有過分析。

node 節點數組插入到元素中
nodes.forEach(function(node) {
  if (copyByClone) node = node.cloneNode(true)
  else if (!parent) return $(node).remove()

  parent.insertBefore(node, target)
  ...
})

如果需要復制節點時(即集合元素的數量大于 1 時),用 node 節點方法 cloneNode 來復制節點,參數 true 表示要將節點的子節點和屬性等信息也一起復制。為什么集合元素大于 1 時需要復制節點呢?因為 insertBefore 插入的是節點的引用,對集合中所有元素的遍歷操作,如果不克隆節點,每個元素所插入的引用都是一樣的,最后只會將節點插入到最后一個元素中。

如果父節點不存在,則將 node 刪除,不再進行后續操作。

將節點用 insertBefore 方法插入到元素中。

處理 script 標簽內的腳本
if (parentInDocument) traverseNode(node, function(el) {
  if (el.nodeName != null && el.nodeName.toUpperCase() === "SCRIPT" &&
      (!el.type || el.type === "text/javascript") && !el.src) {
    var target = el.ownerDocument ? el.ownerDocument.defaultView : window
    target["eval"].call(target, el.innerHTML)
  }
})

如果父元素在 document 內,則調用 traverseNode 來處理 node 節點及 node 節點的所有子節點。主要是檢測 node 節點或其子節點是否為不指向外部腳本的 script 標簽。

el.nodeName != null && el.nodeName.toUpperCase() === "SCRIPT"

這段用來判斷是否為 script 標簽,通過 nodenodeName 屬性是否為 script 來判斷。

!el.type || el.type === "text/javascript"

不存在 type 屬性,或者 type 屬性為 "text/javascript"。這里表示只處理 javascript,因為 type 屬性不一定指定為 text/javascript ,只有指定為 test/javascript 或者為空時,才會按照 javascript 來處理。見MDN文檔

最后,所有文章都會同步發送到微信公眾號上,歡迎關注,歡迎提意見:

作者:對角另一面

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/83308.html

相關文章

  • Zepto源碼Data模塊

    摘要:的模塊用來獲取節點中的屬性的數據,和儲存跟相關的數據。獲取節點指定的緩存值。如果存在,則刪除指定的數據,否則將緩存的數據全部刪除。為所有下級節點,如果為方法,則節點自身也是要被移除的,所以需要將自身也加入到節點中。 Zepto 的 Data 模塊用來獲取 DOM 節點中的 data-* 屬性的數據,和儲存跟 DOM 相關的數據。 讀 Zepto 源碼系列文章已經放到了github上,歡...

    wua_wua2012 評論0 收藏0
  • Zepto源碼Form模塊

    摘要:模塊處理的是表單提交。表單提交包含兩部分,一部分是格式化表單數據,另一部分是觸發事件,提交表單。最終返回的結果是一個數組,每個數組項為包含和屬性的對象。否則手動綁定事件,如果沒有阻止瀏覽器的默認事件,則在第一個表單上觸發,提交表單。 Form 模塊處理的是表單提交。表單提交包含兩部分,一部分是格式化表單數據,另一部分是觸發 submit 事件,提交表單。 讀 Zepto 源碼系列文章已...

    陳江龍 評論0 收藏0
  • Zepto源碼代碼結構

    摘要:源碼結構整體結構如果在編輯器中將的源碼折疊起來,看到的就跟上面的代碼一樣。參考源碼分析代碼結構對象思想與源碼分析設計和源碼分析源碼中關于的問題最后,所有文章都會同步發送到微信公眾號上,歡迎關注歡迎提意見 雖然最近工作中沒有怎么用 zepto ,但是據說 zepto 的源碼比較簡單,而且網上的資料也比較多,所以我就挑了 zepto 下手,希望能為以后閱讀其他框架的源碼打下基礎吧。 源碼版...

    warkiz 評論0 收藏0
  • Zepto源碼Stack模塊

    摘要:讀源碼系列文章已經放到了上,歡迎源碼版本本文閱讀的源碼為改寫原有的方法模塊改寫了以上這些方法,這些方法在調用的時候,會為返回的結果添加的屬性,用來保存原來的集合。方法的分析可以看讀源碼之模塊。 Stack 模塊為 Zepto 添加了 addSelf 和 end 方法。 讀 Zepto 源碼系列文章已經放到了github上,歡迎star: reading-zepto 源碼版本 本文閱讀的...

    crossea 評論0 收藏0
  • Zepto源碼assets模塊

    摘要:模塊是為解決移動版加載圖片過大過多時崩潰的問題。因為沒有處理過這樣的場景,所以這部分的代碼解釋不會太多,為了說明這個問題,我翻譯了這篇文章作為附文怎樣處理移動端對圖片資源的限制,更詳細地解釋了這個模塊的應用場景。 assets 模塊是為解決 Safari 移動版加載圖片過大過多時崩潰的問題。因為沒有處理過這樣的場景,所以這部分的代碼解釋不會太多,為了說明這個問題,我翻譯了《How to...

    thursday 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<