DOM--节点操作
我們知道,DOM主要是對元素進行增刪改查和綁定事件,那么獲取元素作為前提,就顯得格外的
重要。獲取元素通常使用兩種方式:
(1)??利用 DOM 提供的方法獲取元素? ? ? ? ? ? ? (2)? 利用節(jié)點層級關(guān)系獲取元素
DOM提供的方法,在前面的文章里已經(jīng)介紹過了,就是?document.getElementById()
document.getElementsByTagName()、document.querySelector 等。這些方法其實邏輯性不強、
而且相對來說有些繁瑣。
所以,本文將介紹第二種方式--利用節(jié)點關(guān)系來獲取元素,以及進行節(jié)點操作。
1. 節(jié)點概述
網(wǎng)頁中所有內(nèi)容都是節(jié)點(標簽、屬性、文本、注釋等),在DOM 中,節(jié)點使用 node 來表示。
HTML DOM 樹(如下圖所示)中的所有節(jié)點均可通過 JavaScript 進行訪問,所有 HTML 元素(節(jié)點)均可被修改,也可以創(chuàng)建或刪除。
一般地,節(jié)點至少擁有nodeType(節(jié)點類型)、nodeName(節(jié)點名稱)和nodeValue(節(jié)點值)這三個基本屬性。?
① 元素節(jié)點 nodeType 為 1
② 屬性節(jié)點 nodeType 為 2
③ 文本節(jié)點 nodeType 為 3 (文本節(jié)點包含文字、空格、換行等)
我們在實際開發(fā)中,節(jié)點操作主要操作的是元素節(jié)點。
2.?節(jié)點層級
利用 DOM 樹可以把節(jié)點劃分為不同的層級關(guān)系,常見的是父子兄層級關(guān)系。?
2.1. 父級節(jié)點
node.parentNode? 或 node.parentElement
① parentNode 屬性 / parentElement 屬性的用法一致,沒有區(qū)別,都可返回某節(jié)點的父節(jié)點,注意是最近的一個父節(jié)點
② 如果指定的節(jié)點沒有父節(jié)點則返回 null??
2.2?子節(jié)點?
1. parentNode.childNodes
parentNode.childNodes 返回包含指定節(jié)點的所有子節(jié)點的集合,該集合為即時更新的集合。
注意:返回值里面包含了所有的子節(jié)點,包括元素節(jié)點,文本節(jié)點等。因此,如果只想要獲得里面的元素節(jié)點,則需要專門處理。 所以我們一般不提倡使用childNodes。
2. parentNode.children
parentNode.children 是一個只讀屬性,返回所有的子元素節(jié)點。它只返回子元素節(jié)點,其余節(jié)點不返回 (這個是我們重點掌握的)。
3. parentNode.firstChild
4. parentNode.lastChild
firstChild 返回第一個子節(jié)點,找不到則返回null。同樣,也是包含所有的節(jié)點,即包含文本節(jié)點。?lastChild 返回最后一個子節(jié)點,找不到則返回null。同樣,也是包含所有的節(jié)點。
5. parentNode.firstElementChild?
6. parentNode.lastElementChild
?firstElementChild 返回第一個子元素節(jié)點,找不到則返回null。lastElementChild 返回最后一個子元素節(jié)點,找不到則返回null。但是這兩個方法有兼容性問題,IE9 以上才支持。
實際開發(fā)中,firstChild 和 lastChild 包含其他節(jié)點,操作不方便,而 firstElementChild 和?
lastElementChild 又有兼容性問題,那么我們如何獲取第一個子元素節(jié)點或最后一個子元素節(jié)點呢?
解決方案:
1. 如果想要第一個子元素節(jié)點,可以使用 parentNode.chilren[0]?
2. 如果想要最后一個子元素節(jié)點,可以使用 parentNode.chilren[parentNode.chilren.length - 1]。
2.3 案例:下拉菜單
<!-- css樣式 --> <style>* {margin: 0;padding: 0;box-sizing: border-box;}body {background-color: #F5F5F5;}li {list-style: none;}#select {height: 50px;margin: 50px;background-color: #eee;}#select>li {float: left;width: 100px;height: 50px;line-height: 50px;text-indent: 5px;}a {color: #666;text-decoration: none;}a:hover {color: #F83C3D;}#select ul {display: none;font-size: 14px;width: 100px;background-color: #fff;} </style> <body><ul id="select"><li><a href="#">我的淘寶</a><ul><li>已買到的寶貝</li><li>我的足跡</li></ul></li><li><a href="#">我的收藏</a><ul><li>收藏的寶貝</li><li>收藏的店鋪</li><li>收藏的主播</li></ul></li><li><a href="#">聯(lián)系客服</a><ul><li>賣家客服</li><li>消費者客服</li><li>意見反饋</li></ul></li></ul><script>// 1. 獲取元素let lis = document.querySelectorAll("#select>li");// 2. 通過遍歷給每個li綁定鼠標移入移出事件for (let i = 0; i < lis.length; i++) {lis[i].onmouseover = function() {// 鼠標移入該li背景色變成白色this.style.backgroundColor = '#fff';// 對應(yīng)的下拉菜單顯示(下拉菜單是該li 的第二個孩子,下標從0開始)lis[i].children[1].style.display = 'block';};lis[i].onmouseout = function() {// 鼠標移出該li背景色變回原來顏色this.style.backgroundColor = '';// 對應(yīng)的下拉菜單隱藏lis[i].children[1].style.display = 'none';}}</script> </body>案例分析:?
① 導(dǎo)航欄里面的li 都要有鼠標經(jīng)過效果,所以需要循環(huán)注冊鼠標事件
② 核心原理: 當鼠標經(jīng)過 li 里面的 第二個孩子 ul 顯示, 當鼠標離開,則ul 隱藏。
本案例就是合理的利用了不同元素之間的節(jié)點關(guān)系,從而方便而快速的實現(xiàn)了下拉效果。
2.3?兄弟節(jié)點?
1. node.nextSibling
2. node.previousSibling
nextSibling 返回當前元素的下一個兄弟節(jié)點,找不到則返回null。同樣,也是包含所有的節(jié)點。?previousSibling 返回當前元素上一個兄弟節(jié)點,找不到則返回null。同樣,也是包含所有的節(jié)點。由于獲取到的節(jié)點包括所有節(jié)點,所以不推薦使用。
3. node.nextElementSibling
4. node.previousElementSibling
nextElementSibling 返回當前元素下一個兄弟元素節(jié)點,找不到則返回null。previousElementSibling 返回當前元素上一個兄弟元素節(jié)點,找不到則返回null。但是這兩個方法有兼容性問題, IE9 以上才支持。?
如何解決兼容性問題 ?
——?自己封裝一個兼容性的函數(shù),如下:
function getNextElementSibling(element) {var el = element;while (el = el.nextSibling) {if (el.nodeType === 1) {return el;}}return null; }3.創(chuàng)建節(jié)點
document.createElement('tagName');?
如:document.createElement(‘li’)? // 動態(tài)創(chuàng)建了一個li節(jié)點
document.createElement() 方法創(chuàng)建由 tagName 指定的 HTML 元素。因為這些元素原先不存在,
是根據(jù)我們的需求動態(tài)生成的,所以我們也稱為動態(tài)創(chuàng)建元素節(jié)點。??
4.添加節(jié)點
1. node.appendChild(child)
node.appendChild() 方法將一個節(jié)點添加到指定父節(jié)點的子節(jié)點列表末尾。類似于 CSS 里面的?
after 偽元素。
?2. node.insertBefore(child, 指定元素)?
node.insertBefore() 方法將一個節(jié)點添加到父節(jié)點的指定子節(jié)點前面。類似于 CSS 里面的 before?
偽元素。
5.?刪除節(jié)點
node.removeChild(child)?
node.removeChild() 方法從 DOM 中刪除一個子節(jié)點,返回刪除的節(jié)點,node是要刪除節(jié)點的父節(jié)點(親生的/最近的那個父節(jié)點)
?
6.案例:簡單版發(fā)布留言案例
需求:輸入信息,點擊發(fā)送按鈕,頁面上會將剛剛這條信息顯示在留言區(qū)域的最上方。并且每生成的這條信息都自帶一個刪除按鈕,用來刪除本條信息。
<!-- css樣式 --> <style>* {margin: 0;padding: 0;box-sizing: border-box;}.box {width: 400px;margin: 50px;}.box_send textarea {width: 300px;height: 160px;outline: none;resize: none;}.box_send button {padding: 5px 15px;vertical-align: bottom;}.box_message {margin-top: 15px;}.box_message li {width: 300px;line-height: 34px;font-size: 14px;text-indent: 5px;color: #666;list-style: none;border-bottom: 1px dashed #ccc;}.box_message li a {float: right;} </style> <body><div class="box"><div class="box_send"><textarea id="send_data"></textarea><button id="btnSend">發(fā)布</button></div><div class="box_message"><ul></ul></div></div><script>// 1. 獲取元素let textarea = document.getElementById("send_data");let btn = document.getElementById("btnSend");let ul = document.querySelector(".box_message ul");// 2. 給發(fā)布按鈕綁定點擊事件btn.onclick = function() {// 使用value獲取文本域里的值,并且做非空判斷// trim() 方法用于去除文本兩端的空格,那么只輸入空格也是無效內(nèi)容if (textarea.value.trim().length <= 0) {return alert('請輸入內(nèi)容!');}// 在確定輸入內(nèi)容有效后,開始創(chuàng)建節(jié)點lilet li = document.createElement('li');// 把li 節(jié)點添加至ul 中,由于最新發(fā)布的顯示在最上方,所以使用insertBefore()ul.insertBefore(li, ul.children[0]);// 給li添加內(nèi)容(即把文本域里的內(nèi)容賦值給li,同時給li里添加一個刪除鏈接,用來刪除本條內(nèi)容)li.innerHTML = textarea.value + '<a href="javascript:;">刪除</a>';// 先獲取a 再給 a 綁定點擊事件let a = document.querySelector('a');a.onclick = function() {// 在刪除前先提醒用戶let flag = confirm("您確定刪除嗎?");// 如果確定,則執(zhí)行刪除操作if (flag) {// 刪除本條數(shù)據(jù),即刪除它的父親ul.removeChild(this.parentNode);}};// 添加成功后,將文本域內(nèi)容清空,方便下次輸入內(nèi)容發(fā)布textarea.value = '';};</script> </body>案例分析:
① 核心思路: 點擊按鈕之后,就動態(tài)創(chuàng)建一個li,添加到ul 里面。
② 創(chuàng)建li 的同時,把文本域里面的值通過li.innerHTML 賦值給 li
③ 如果想要新的留言后面顯示就用 appendChild 如果想要前面顯示就用insertBefore
④ 當我們把文本域里面的值賦值給li 的時候,多添加一個刪除的鏈接
⑤ 需要把鏈接獲取過來,當我們點擊當前的鏈接的時候,刪除當前鏈接所在的li
⑥ 阻止鏈接跳轉(zhuǎn)需要添加 javascript:void(0); 或者 javascript:;
7.復(fù)制節(jié)點(克隆節(jié)點)
node.cloneNode()
node.cloneNode() 方法返回調(diào)用該方法的節(jié)點的一個副本。 也稱為克隆節(jié)點/拷貝節(jié)點??
注意:
1. 如果括號參數(shù)為空或者為 false ,則是淺拷貝,即只克隆復(fù)制節(jié)點本身,不克隆里面的子節(jié)點。
2. 如果括號參數(shù)為 true ,則是深度拷貝,會復(fù)制節(jié)點本身以及里面所有的子節(jié)點。?
總結(jié)
- 上一篇: 如何绕过wegame下载英雄联盟
- 下一篇: 管理之道(十八) - 跳起来够得着的目标