讀zepto核心源碼學習JS筆記(4)--$.fn

根據第一篇總體框架,能夠知道$()方法返回的Z函數的實例化;而Z的原型又指向$.fn;因此通過$()處理過的對象,均可以使用$.fn中的方法;
這一篇就記錄一下讀$.fn的筆記;css

zepto.Z.prototype = Z.prototype = $.fn

一 內部函數

zepto.match

//判斷一個元素是否匹配給定的選擇器
zepto.matches = function(element, selector) {
    //若是selector,element沒值或者element是普通節點
    if (!selector || !element || element.nodeType !== 1) return false
    var matchesSelector = element.matches || element.webkitMatchesSelector ||
                          element.mozMatchesSelector || element.oMatchesSelector ||
                          element.matchesSelector
    if (matchesSelector) return matchesSelector.call(element, selector)
    // fall back to performing a selector:
    var match, parent = element.parentNode, temp = !parent
    if (temp) (parent = tempParent).appendChild(element)
    match = ~zepto.qsa(parent, selector).indexOf(element)
    temp && tempParent.removeChild(element)
    return match
 }
  • 若是瀏覽器支持matchesSelector方法,則用此方法進行判斷

    html

  • 若是瀏覽器不支持matchesSelector,則定義matchparent變量,其中parentelement的父元素,若是沒有父元素,則建立一個div容器看成其父元素java

    tempParent = document.createElement('div'),node

    match = ~zepto.qsa(parent, selector).indexOf(element)web

    qsa()函數以前已經說明,若element不存在zepto.qsa(parent, selector).中,則返回-1,~-1即爲0,即match最終的值爲false數組

    element存在,則返回非零的值,轉換爲布爾值爲true瀏覽器

二 $.fn

constructor

constructor: zepto.Z,app

  • 這就涉及到原型和構造函數的知識.以後會看成一個專題來記錄;這裏只作簡單介紹;
var person = function(name){
this.name = name;
}
var siva = new Person('Siva');
siva .__proto__ == person.prototype //true
person.prototype.constructor == person //true

因爲zepto.Z.prototype = $.fn ;所以$.fn的構造函數即爲zepto.Z框架

forEach

forEach: emptyArray.forEach,dom

  • 以前已經說過,emptyArray爲定義的一個空數組,因此這裏的forEach即爲Array.prototype.forEach,能夠理解爲數組自帶的forEach方法;

reduce,push,sort,splice,indexOf

reduce: emptyArray.reduce,
push: emptyArray.push,
sort: emptyArray.sort,
splice: emptyArray.splice,
indexOf: emptyArray.indexOf,
  • 道理同上

get

get: function(idx){
//若是不傳參,將Z對象轉爲數組, slice.call()在第三篇已經提到過;數組自有的slice;
//若是傳參小於0,就將傳的參數轉換爲idx加上傳入對象的長度;即爲倒數返回;
//例如傳入的值爲-1;則選取最後一個元素
  return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
},

在分析這句話以前,咱們先看看get的用法;

toArray

//將Z對象集合轉換成數組
toArray: function(){ return this.get() },
  • 不傳參調用get()

concat

concat: function(){
  var i, value, args = []
  for (i = 0; i < arguments.length; i++) {
    value = arguments[i]
    //若是其中傳入的參數爲Z對象,則將其轉爲數組;並將值傳給arg
    args[i] = zepto.isZ(value) ? value.toArray() : value
  }
  //apply方法將this強制綁定到調用concat的對象身上
  //若是調用concat的是Z對象,則將其轉換成數組
  return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
},
  • 添加元素到一個Zepto對象集合造成一個新數組。若是參數是一個數組,那麼這個數組中的元素將會合併到Zepto對象集合中。
  • arguments爲傳入的參數組合;

  • 這個方法並無像上面的reduce,push,sort,splice,等直接複製Array.prototype的屬性,是由於調用此事件的對象並不必定爲數組,若是調用的對象爲$();則是類數組對象,而不是真正的數組,若是直接調用數組的concat,則會將$();看成數組的一個item合併起來,因此此方法須要從新封裝

slice

slice: function(){
//同上,將this強制綁定到調用的對象身上;
  return $(slice.apply(this, arguments))
},

ready

ready: function(callback){
//判斷dom是否ready,若是已經ready,直接執行函數
  if (readyRE.test(document.readyState) && document.body) callback($)
  //不然註冊監聽器;
  else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
  return this
},
  • readyRE = /complete|loaded|interactive/,

  • document.readyState返回當前文檔的狀態,該屬性返回四個值;分別爲:
    • uninitialized - 還未開始載入
    • loading - 載入中
    • interactive - 已加載,文檔與用戶能夠開始交互 ---僅DOM加載完成,不包括樣式表,圖片,flash,觸發DOMContentLoaded事件
    • complete - 載入完成 ---頁面上全部的DOM,樣式表,腳本,圖片,flash都已經加載完成了,開始觸發load事件

size

size: function() {
  return this.length
},
  • 返回所選集合的length屬性的值;

each

each: function(callback){
  emptyArray.every.call(this, function(el, idx){
    return callback.call(el, idx, el) !== false
  })
  //可使用鏈式操做
  return this
},
  • 方法內部調用了every,當callback的值返回false的時候就會停止循環;

eq

eq: function(idx){
  return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
},
  • 當idx爲-1的時候.取最後一個;

first

first: function(){
  var el = this[0]
  return el && !isObject(el) ? el : $(el)
},
  • this[0] 取集合中的第一個值;
  • return el && !isObject(el) ? el : $(el) 若是集合中第一個數據爲對象的話返回自己,不然轉換成zepto對象

last

last: function(){
  var el = this[this.length - 1]
  return el && !isObject(el) ? el : $(el)
},
  • 同上

add

add: function(selector,context){
  return $(uniq(this.concat($(selector,context))))
},
uniq = function(array){ 
    return filter.call(array, 
    function(item, idx){ return array.indexOf(item) == idx })
}
  • 添加元素到當前匹配的元素集合中
  • uniq中的filter在以前已經定義;filter = emptyArray.filter,即爲Array.prototype.filter

    • Array.prototype.filter的用法
      java var words = ["spray", "limit", "elite", "exuberant", "destruction", "present"]; var longWords = words.filter(function(word){ return word.length > 6; }) // Filtered array longWords is ["exuberant", "destruction", "present"]
  • uniq的做用是給數組去重,若是數組中的數據在數組中的位置不等於索引值,說明這個數據在數組中出現過兩次以上,咱們再利用filter函數,只取出位置和索引值相同的那個;

map

map: function(fn){
  return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
},

remove

remove: function(){
  return this.each(function(){
    if (this.parentNode != null)
      this.parentNode.removeChild(this)
  })
},
  • 從其父節點中刪除當前集合中的元素,有效的從dom中移除。

is

is: function(selector){
  return this.length > 0 && zepto.matches(this[0], selector)
},
  • 判斷當前元素集合中的第一個元素是否符css選擇器。
  • match在開頭已經寫過了;

not

not: function(selector){
  var nodes=[]
  //當selector爲函數時,可是safari下的typeof odeList也是function,
  //因此這裏須要再加一個判斷selector.call !== undefined
  if (isFunction(selector) && selector.call !== undefined)
    this.each(function(idx){
    //當selector.call(this,idx)返回結果爲false,記錄;
      if (!selector.call(this,idx)) nodes.push(this)
    })
  else {
  //當selector爲字符串的時候,篩選知足selector的記錄;
    var excludes = typeof selector == 'string' ? this.filter(selector) :
    //當selector爲類數組,將其變爲數組,不然,執行$()
      (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
    this.forEach(function(el){
    //篩選出不在excludes中的數據
      if (excludes.indexOf(el) < 0) nodes.push(el)
    })
  }
  //以上獲得的是數組,將其轉換成zepto對象;
  return $(nodes)
},

attr

attr: function(name, value){
  var result
  //若是name爲字符串的時候,且只有一個參數
  return (typeof name == 'string' && !(1 in arguments)) ?
  //調用者第一個對象的節點屬性爲普通元素,若是有這個屬性,就返回這個屬性值,不然返回undefined;
  //獲取屬性
    (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) :
 //修改屬性
    this.each(function(idx){
      if (this.nodeType !== 1) return
     //若是name是一個對象,則遍歷,設置屬性;
      if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
      //若是不是對象,利用funcArg獲取返回值
      else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
    })
},
  • 用法---讀取或設置dom的屬性;
attr(name)   ⇒ string
attr(name, value)   ⇒ self
attr(name, function(index, oldValue){ ... })   ⇒ self
attr({ name: value, name2: value2, ... })   ⇒ self
var form = $('form')
form.attr('action')             //=> 讀取值
form.attr('action', '/create')  //=> 設置值
form.attr('action', null)       //=> 移除屬性
form.attr({
  action: '/create',
  method: 'post'
})// 多個屬性:
  • setAttribute
function setAttribute(node, name, value) {
    value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
}
* 當傳入的`value`爲空的時候,去除屬性,不然設置屬性爲`value`
  • funcArg
function funcArg(context, arg, idx, payload) {
    return isFunction(arg) ? arg.call(context, idx, payload) : arg
}
* 當`arg`爲函數的時候,將參數傳入arg函數內,不然返回本身

removeAttr

removeAttr: function(name){
      return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){
        setAttribute(this, attribute)
      }, this)})
 },
  • 移除當前對象集合中全部元素的指定屬性.

prop

prop: function(name, value){
      name = propMap[name] || name
      //若是傳入value值
      return (1 in arguments) ?
        this.each(function(idx){
          this[name] = funcArg(this, value, idx, this[name])
        }) :
        //不然沒有value,返回第一條數據的name
        (this[0] && this[0][name])
},
  • 用法:讀取或設置dom元素的屬性值。它在讀取屬性值的狀況下優先於 attr,由於這些屬性值會由於用戶的交互發生改變,如checkedselected
prop(name)   ⇒ value
prop(name, value)   ⇒ self
prop(name, function(index, oldValue){ ... })   ⇒ self
  • propMap
propMap = {
      'tabindex': 'tabIndex',
      'readonly': 'readOnly',
      'for': 'htmlFor',
      'class': 'className',
      'maxlength': 'maxLength',
      'cellspacing': 'cellSpacing',
      'cellpadding': 'cellPadding',
      'rowspan': 'rowSpan',
      'colspan': 'colSpan',
      'usemap': 'useMap',
      'frameborder': 'frameBorder',
      'contenteditable': 'contentEditable'
},

removeProp

removeProp: function(name){
      name = propMap[name] || name
      return this.each(function(){ delete this[name] })
},
  • 用法:從集合的每一個DOM節點中刪除一個屬性。
  • 沒法刪除classNamemaxLength屬性;由於瀏覽器禁止;

pluck

pluck: function(property){
      return $.map(this, function(el){ return el[property] })
},
  • 獲取對象集合中每個元素的屬性值。返回值爲 nullundefined值得過濾掉。
  • $.map在第二篇已經提到過;
相關文章
相關標籤/搜索