2019-01-05

封裝 DOM 操作

DOM 將文檔(頁(yè)面結(jié)構(gòu))表示成一棵將樹,樹由元素節(jié)點(diǎn),屬性節(jié)點(diǎn),文本節(jié)點(diǎn)組成,而 <html> 即是樹的根。BOM 頂級(jí)窗口 window 包含了 document 屬性,可以理解為 BOM 包含了 DOM,她就是代表了當(dāng)前頁(yè)面的 HTMLDocument 對(duì)象,因此可以通過(guò)她來(lái)操作文檔內(nèi)容和結(jié)構(gòu)。

注意:操作節(jié)點(diǎn)時(shí)務(wù)必要降低性能開銷問(wèn)題。

MDN Web API 參考文檔
示例源碼

關(guān)于 DOM 的幾個(gè)知識(shí)點(diǎn)

訪問(wèn)節(jié)點(diǎn)時(shí),可以遍歷節(jié)點(diǎn)組,依據(jù)以下三個(gè) nodeType 來(lái)匹配所需的節(jié)點(diǎn)類型。鑒于現(xiàn)代瀏覽器都提供了更便利的 API,所以下面的節(jié)點(diǎn)訪問(wèn)都是利用直接作用于元素節(jié)點(diǎn)的接口。

  • nodeType 1 表示元素節(jié)點(diǎn)
  • nodeType 2 表示屬性節(jié)點(diǎn)
  • nodeType 3 表示文本節(jié)點(diǎn)
  • DOM 操作主要是對(duì)三大節(jié)點(diǎn)進(jìn)行 添加、刪除、修改、替換。其中就涉及了節(jié)點(diǎn)的訪問(wèn)操作,包括了訪問(wèn)子節(jié)點(diǎn)、父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)、文本節(jié)點(diǎn)、屬性節(jié)點(diǎn)等。

下面的示例僅包含上面所談到的知識(shí)點(diǎn)。


getElement 接口 $

  • 該接口便利于我們通過(guò) [類名|ID名|標(biāo)簽名] 直接獲取相匹配的節(jié)點(diǎn)對(duì)象
function $(str) {
  str = str ? str.trim() : ''
  if (!str) {
    return false
  }
  var tag = str.charAt(0)
  var name = str.substr(1)
  switch(tag) {
    case '#':
      return document.getElementById(name)
      break
    case '.':
      return document.getElementsByClassName(name)
      break
    default:
      return document.getElementsByTagName(str)
  }
}


關(guān)系型節(jié)點(diǎn)訪問(wèn)接口

關(guān)系型在這里表示為在 DOM 樹中沿樹枝,樹葉,上下左右方向訪問(wèn)的意思。

var el = typeof str === "string" ? $(str) : str

這段代碼在每個(gè)訪問(wèn)接口都需求到,即傳入 [類名|ID名|標(biāo)簽名|DOM object] 都可以,下面拿訪問(wèn)父級(jí)節(jié)點(diǎn)(向上訪問(wèn)只能是元素節(jié)點(diǎn))來(lái)說(shuō)。

function parentNode(str) {
  var el = typeof str === "string" ? $(str) : str
  // IE el.parentElement
  return el.length ? el[0].parentNode : el.parentNode
}

對(duì),如你所見,這里 封裝 的很多的接口都是類似的,只是目標(biāo)不同,所以拿幾個(gè)獻(xiàn)丑就夠了!

function firstChildNode(str) {
  var el = typeof str === "string" ? $(str) : str
  // firstChild 包含文本節(jié)點(diǎn)
  return el.length ? el[0].firstElementChild : el.firstElementChild
}

之前對(duì)瀏覽器提供的關(guān)系型節(jié)點(diǎn)訪問(wèn) API 一直分不清楚,現(xiàn)在也記不清,所以...,發(fā)揮爛筆頭的用處吧,區(qū)分開哪個(gè) api name 會(huì)包含元素節(jié)點(diǎn)或同時(shí)文本節(jié)點(diǎn)。結(jié)果發(fā)現(xiàn)子節(jié)點(diǎn) children 和父節(jié)點(diǎn) parentNode 特殊點(diǎn)(元素節(jié)點(diǎn)),含 *Nodes*Child 的幾乎都是包括文本節(jié)點(diǎn)的。而含 *Element* 都是元素節(jié)點(diǎn),于是我將它們都改成了純?cè)毓?jié)點(diǎn)接口。

lastElementChild previousElementSibling nextElementSibling 三個(gè)都是訪問(wèn)元素節(jié)點(diǎn)的,感覺還是不好記,易混淆。

節(jié)點(diǎn)操作

來(lái)看一個(gè)不實(shí)用的添加節(jié)點(diǎn)的接口,其功能是創(chuàng)建一新節(jié)點(diǎn),然后在給定元素的子集合里將新節(jié)點(diǎn)追加到尾部或添加到頭部。

/**
 * @param {string} tagName 要?jiǎng)?chuàng)建的標(biāo)簽名
 * @param {string} msg 新建標(biāo)簽名下的文本節(jié)點(diǎn) | 元素和文本節(jié)點(diǎn)并存
 * @param {boolean} head 是否追加到頭部
 * @param {boolean} tag 是否使元素、屬性、文本節(jié)點(diǎn)并存
 */
function addNode(str, tagName, msg, head, tag) {
  var el = typeof str === "string" ? $(str) : str
  var newNode = document.createElement(tagName.trim())
  head = typeof head === 'boolean' ? head : false
  tag = typeof tag === 'boolean' ? tag : true
  el = el.length ? el[0] : el
  if (msg) {
    if (tag) {
      newNode.innerHTML = msg
    } else {
      // '<code>Be happy.</code>' print as string.
      newNode.innerText = msg
    }
  }

  if (head) {
    el.insertBefore(newNode, firstChildNode(el))
  } else {
    el.appendChild(newNode)
  }
}

addNode('#ad', 'h3', '<strong>買十送零活動(dòng)</strong>', true)
addNode('.box', 'div', 'add <div></div> string', false, false)


此函數(shù)功能為刪除給定元素下符合條件的元素節(jié)點(diǎn),傳一個(gè)參數(shù)則表示全刪。條件可以是指定要?jiǎng)h除的標(biāo)簽名和刪除第幾個(gè)。有幾個(gè)自定義的接口,看名字就可以知道她是能干嘛的,如 childNodes。

/**
 * @param {string} nodeName 指定標(biāo)簽名的約束條件
 * @param {number} nth 指定索引的約束條件
 */
function delNode(str, nodeName, nth) {
  var children = childNodes(str, true)
  if (nth && children.length > 0) {
    for (var i = 0, n = 1; i < children.length; i++) {
      if (children[i].localName === nodeName) {
        if (n === nth) {
          // 找到了
          parentNode(children[i]).removeChild(children[i])
          break
        }
        n++
      }
    }
    return
  }

  // 不能在循環(huán)里面直接刪,會(huì)導(dǎo)致索引變更
  var delArr = []
  for (var i = 0; i < children.length; i++) {
    if (!nodeName) {
      delArr.push(children[i])
    } else if (children[i].localName === nodeName) {
      // or nodeName 該方法返回的都是大寫的
      delArr.push(children[i])
    }
  }

  delArr.forEach(function (value) {
    parentNode(value).removeChild(value)
  })
}

delNode('#msg', 'div', 3)  // 將ID為msg元素下的第三個(gè) div 刪掉
delNode('#msg', 'div')  // 將ID為msg元素下 div 全刪掉


屬性節(jié)點(diǎn)操作

直接上代碼,看注釋吧!

/**
 * 設(shè)置元素自定義屬性值
 * @param {object} item 屬性鍵值對(duì)
 */
function setAttr(str, item) {
  var el = typeof str === "string" ? $(str) : str
  el = el.length ? el[0] : el
  for (var key in item) {
    // or document.createAttribute(key) 創(chuàng)建屬性節(jié)點(diǎn)添加
    // 自定義屬性若包含樣式,DOM 樣式是不會(huì)生效的
    el.setAttribute(key, item[key])
  }
}
/**
 * 添加元素指定的類名
 * @param {string} name 待添加的類名
 */
function addClass(str, name) {
  var el = typeof str === "string" ? $(str) : str
  el = el.length ? el[0] : el
  if (!el.classList.contains(name)) {
    // or className + ' newClassName' 字符串追加
    el.classList.add(name)
  }
}

The last one.

/**
 * 設(shè)置元素的行內(nèi)樣式屬性值
 * @param {object} obj 樣式屬性鍵值
 */
function setStyle(str, obj) {
  var el = typeof str === "string" ? $(str) : str
  el = el.length ? el[0] : el
  // el.style.* 只能設(shè)置行內(nèi)樣式
  for (var key in obj) {
    el.style[key] = obj[key]
  }
}

setStyle('.wrapper', {color: 'pink', opacity: '0.5'})


以上所記錄的只是瀏覽器提供的 API 里的冰山一角,無(wú)法在這兒一一列舉,我們只需認(rèn)識(shí)到她們大多都能夠一針見血,有著 WYSIWYG 神話般的效果,待需要時(shí),再現(xiàn)學(xué)現(xiàn)用就好啦。

End.
若有不足,還請(qǐng)高人指教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ??DOM(文檔對(duì)象模型)是針對(duì) HTML 和 XML 文檔的一個(gè) API(應(yīng)用程序編程接口)。 ??DOM 描繪...
    霜天曉閱讀 3,864評(píng)論 0 7
  • 第3章 基本概念 3.1 語(yǔ)法 3.2 關(guān)鍵字和保留字 3.3 變量 3.4 數(shù)據(jù)類型 5種簡(jiǎn)單數(shù)據(jù)類型:Unde...
    RickCole閱讀 5,504評(píng)論 0 21
  • ??DOM 1 級(jí)主要定義的是 HTML 和 XML 文檔的底層結(jié)構(gòu)。 ??DOM2 和 DOM3 級(jí)則在這個(gè)結(jié)構(gòu)...
    霜天曉閱讀 1,599評(píng)論 1 3
  • 之前通過(guò)深入學(xué)習(xí)DOM的相關(guān)知識(shí),看了慕課網(wǎng)DOM探索之基礎(chǔ)詳解篇這個(gè)視頻(在最近看第三遍的時(shí)候,準(zhǔn)備記錄一點(diǎn)東西...
    微醺歲月閱讀 4,760評(píng)論 2 61
  • 死亡 死亡只是一種儀式 不過(guò)是將以往 散落的詩(shī)句 收集在一起 裝訂成冊(cè) 然后付之于火 死亡只是一種形式 一炷香 兩...
    皮三9099閱讀 355評(píng)論 1 2

友情鏈接更多精彩內(nèi)容