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