成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Zepto這樣操作元素屬性

付倫 / 1240人閱讀

摘要:還有一點(diǎn)需要注意的是方法設(shè)置或者獲取都是在操作元素的屬性,那它和,的區(qū)別在哪呢可以查看設(shè)置設(shè)置與的設(shè)置部分比較類似,既支持直接傳入普通的字符串也支持傳入回調(diào)函數(shù)。

前言

使用Zepto的時(shí)候,我們經(jīng)常會(huì)要去操作一些DOM的屬性,或元素本身的固有屬性或自定義屬性等。比如常見的有attr(),removeAttr(),prop(),removeProp(),data()等。接下來我們挨個(gè)整明白他們是如何實(shí)現(xiàn)的...點(diǎn)擊zepto模塊源碼注釋查看這篇文章對(duì)應(yīng)的解析。

原文鏈接

源碼倉庫

attr()

讀取或設(shè)置dom的屬性。

如果沒有給定value參數(shù),則讀取對(duì)象集合中第一個(gè)元素的屬性值。

當(dāng)給定了value參數(shù)。則設(shè)置對(duì)象集合中所有元素的該屬性的值。當(dāng)value參數(shù)為null,那么這個(gè)屬性將被移除(類似removeAttr),多個(gè)屬性可以通過對(duì)象鍵值對(duì)的方式進(jìn)行設(shè)置。zeptojs_api/#attr

示例

// 獲取name屬性
attr(name)   
// 設(shè)置name屬性        
attr(name, value)
// 設(shè)置name屬性,不同的是使用回調(diào)函數(shù)的形式
attr(name, function(index, oldValue){ ... })
// 設(shè)置多個(gè)屬性值
attr({ name: value, name2: value2, ... })

已經(jīng)知道了如何使用attr方法,在開始分析attr實(shí)現(xiàn)源碼之前,我們先了解一下這幾個(gè)函數(shù)。

setAttribute

function setAttribute(node, name, value) {
  value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
}

它的主要作用就是設(shè)置或者刪除node節(jié)點(diǎn)的屬性。當(dāng)value為null或者undefined的時(shí)候,調(diào)用removeAttribute方法移除name屬性,否則調(diào)用setAttribute方法設(shè)置name屬性。

funcArg

function funcArg(context, arg, idx, payload) {
  return isFunction(arg) ? arg.call(context, idx, payload) : arg
}

funcArg函數(shù)在多個(gè)地方都有使用到,主要為類似attr,prop,val等方法中第二個(gè)參數(shù)可以是函數(shù)或其他類型提供可能和便捷。

如果傳入的arg參數(shù)是函數(shù)類型,那么用context作為arg函數(shù)的執(zhí)行上下文,以及將idx和payload作為參數(shù)去執(zhí)行。否則直接返回arg參數(shù)。

好啦接下來開始看attr的源碼實(shí)現(xiàn)了

attr: function (name, value) {
  var result
  return (typeof name == "string" && !(1 in arguments)) ?
    // 獲取屬性
    (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) :
    // 設(shè)置屬性
    this.each(function (idx) {
      if (this.nodeType !== 1) return
      // 設(shè)置多個(gè)屬性值
      if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
      // 設(shè)置一個(gè)屬性值
      else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
    })
}

代碼分為兩部分,獲取與設(shè)置屬性。先看

獲取部分

typeof name == "string" && !(1 in arguments)) ?
    // 獲取屬性
    (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : "設(shè)置代碼邏輯代碼塊"

當(dāng)name參數(shù)是string類型,并且沒有傳入value參數(shù)時(shí)候,意味著是讀取屬性的情況。緊接著再看當(dāng)前選中的元素集合中第一個(gè)元素是否存在并且節(jié)點(diǎn)類型是否為element類型,如果是,再調(diào)用getAttribute獲取name屬性,結(jié)果不為null或者undefined的話直接返回,否則統(tǒng)一返回undefined。

設(shè)置部分

this.each(function (idx) {
  if (this.nodeType !== 1) return
  // 設(shè)置多個(gè)屬性值
  if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
  // 設(shè)置一個(gè)屬性值
  else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
})

調(diào)用each方法,對(duì)當(dāng)前的元素集合進(jìn)行遍歷操作,遍歷過程中,如果當(dāng)前的元素不是element類型,直接return掉。否則根據(jù)name參數(shù)傳入的是否是對(duì)象進(jìn)行兩個(gè)分支的操作。

如果name是個(gè)對(duì)象,那對(duì)對(duì)象進(jìn)行遍歷,再挨個(gè)調(diào)用setAttribute方法,進(jìn)行屬性設(shè)置操作。

不是對(duì)象的話,接下來的這行代碼,讓第二個(gè)參數(shù)既可以傳入普通的字符串,也可以傳入回調(diào)函數(shù)。

看個(gè)實(shí)際使用的例子

$(".box").attr("name", "qianlongo")

$(".box").attr("name", function (idx, oldVal) {
  return oldVal + "qianlongo"
})

可以看到如果傳入的是回調(diào)函數(shù),那回調(diào)函數(shù)可以接收到元素的索引,以及要設(shè)置的屬性的之前的值。

removeAttr()

移除當(dāng)前對(duì)象集合中所有元素的指定屬性,理論上講attr也可以做到removeAttr的功能。只要將要移除的name屬性設(shè)置為null或者undefined即可。

removeAttr: function (name) {
  return this.each(function () {
  // 通過將name分割,再將需要移除的屬性進(jìn)行遍歷刪除
  this.nodeType === 1 && name.split(" ").forEach(function (attribute) {
    setAttribute(this, attribute)
  }, this)
  })
}

代碼本身很簡(jiǎn)單,對(duì)當(dāng)前選中的元素集合進(jìn)行遍歷操作,然后對(duì)name參數(shù)進(jìn)行空格分割(這樣對(duì)于name傳入類似"name sex age"就可以批量刪除了),最后還是調(diào)用的setAttribute方法進(jìn)行屬性刪除操作。

prop()

讀取或設(shè)置dom元素的屬性值,簡(jiǎn)寫或小寫名稱,比如for, class, readonly及類似的屬性,將被映射到實(shí)際的屬性上,比如htmlFor, className, readOnly, 等等。

直接看源碼實(shí)現(xiàn)

prop: function (name, value) {
  name = propMap[name] || name
  return (1 in arguments) ?
    this.each(function (idx) {
      this[name] = funcArg(this, value, idx, this[name])
    }) :
    (this[0] && this[0][name])
}

通過1 in arguments作為設(shè)置與獲取元素屬性的判斷標(biāo)志,value傳了,則對(duì)當(dāng)前選中的元素集合進(jìn)行遍歷操作,同樣用到了funcArg函數(shù),讓value既可以傳入函數(shù),也可以傳入其他值。與attr方法不同的是,因?yàn)槭窃O(shè)置和獲取元素的固有屬性,所以直接向元素設(shè)置和讀取值就可以了。

需要注意的是當(dāng)你傳入class,for等屬性的時(shí)候需要被映射到className,htmlFor等,下面是映射列表

var 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()

從集合的每個(gè)DOM節(jié)點(diǎn)中刪除一個(gè)屬性

removeProp: function (name) {
  name = propMap[name] || name
  return this.each(function () { delete this[name] })
}

直接通過delete去刪除,但是如果嘗試刪除DOM的一些內(nèi)置屬性,如className或maxLength,將不會(huì)有任何效果,因?yàn)闉g覽器禁止刪除這些屬性。

html()

獲取或設(shè)置對(duì)象集合中元素的HTML內(nèi)容。當(dāng)沒有給定content參數(shù)時(shí),返回對(duì)象集合中第一個(gè)元素的innerHtml。當(dāng)給定content參數(shù)時(shí),用其替換對(duì)象集合中每個(gè)元素的內(nèi)容。content可以是append中描述的所有類型zeptojs_api/#html

源碼分析

html: function (html) {
  return 0 in arguments ?
    this.each(function (idx) {
      var originHtml = this.innerHTML
      $(this).empty().append(funcArg(this, html, idx, originHtml))
    }) :
    (0 in this ? this[0].innerHTML : null)
}

如果html傳了,就遍歷通過append函數(shù)設(shè)置html,沒傳就是獲取(即返回當(dāng)前集合的第一個(gè)元素的innerHTML)注意:這里的html參數(shù)可以是個(gè)函數(shù),接收的參數(shù)是當(dāng)前元素的索引和html。

text()

獲取或者設(shè)置所有對(duì)象集合中元素的文本內(nèi)容。

當(dāng)沒有給定content參數(shù)時(shí),返回當(dāng)前對(duì)象集合中第一個(gè)元素的文本內(nèi)容(包含子節(jié)點(diǎn)中的文本內(nèi)容)。

當(dāng)給定content參數(shù)時(shí),使用它替換對(duì)象集合中所有元素的文本內(nèi)容。它有待點(diǎn)似 html,與它不同的是它不能用來獲取或設(shè)置 HTMLtext

text() ? string

text(content) ? self

text(function(index, oldText){ ... }) ? self

源碼分析

text: function (text) {
  return 0 in arguments ?
    this.each(function (idx) {
      var newText = funcArg(this, text, idx, this.textContent)
      this.textContent = newText == null ? "" : "" + newText
    }) :
    (0 in this ? this.pluck("textContent").join("") : null)
}

同樣包括設(shè)置和獲取兩部分,判斷的邊界則是是否傳入了第一個(gè)參數(shù)。先看獲取部分。

獲取text

(0 in this ? this.pluck("textContent").join("") : null)

0 in this 當(dāng)前是否選中了元素,沒有直接返回null,有則通過this.pluck("textContent").join("")獲取,我們先來看一下pluck做了些什么

plunck

// `pluck` is borrowed from Prototype.js
pluck: function (property) {
  return $.map(this, function (el) { return el[property] })
},

pluck也是掛在原型上的方法之一,通過使用map方法遍歷當(dāng)前的元素集合,返回結(jié)果是一個(gè)數(shù)組,數(shù)組的每一項(xiàng)則是元素的property屬性。所以上面才通過join方法再次轉(zhuǎn)成了字符串。

還有一點(diǎn)需要注意的是text方法設(shè)置或者獲取都是在操作元素的textContent屬性,那它和innerText,innerHTML的區(qū)別在哪呢?可以查看MDN

設(shè)置text

this.each(function (idx) {
  var newText = funcArg(this, text, idx, this.textContent)
  this.textContent = newText == null ? "" : "" + newText
})

設(shè)置與html的設(shè)置部分比較類似,既支持直接傳入普通的字符串也支持傳入回調(diào)函數(shù)。如果得到的newText為null或者undefined,會(huì)統(tǒng)一轉(zhuǎn)成空字符串再進(jìn)行設(shè)置。

val

獲取或設(shè)置匹配元素的值。當(dāng)沒有給定value參數(shù),返回第一個(gè)元素的值。如果是