# 節點層級
## 父子節點
從DOM文檔樹中可以看出,DOM的節點之間存在著關聯關系,我們把從上而下的關聯關系叫做 "父子節點 ",把同一層級(平級)的關系叫做 "兄弟節點"。在實際開發中,我們經常通過操作父子節點來完成相應的頁面效果。節點層級關系通過節點屬性體現,如 parentNode(),childNodes(所有節點,包括換行),children(HTML元素節點)等,以下介紹幾種常用的節點屬性
html和css代碼
~~~
<div id="main">
? ?<span>我是span標簽文本</span>
? ?<p>我是p標簽文本</p>
? ?<!--我是注釋-->
</div>
~~~
JavaScript代碼
~~~
var main = document.getElementById('main');
console.dir(main);
// 1、節點中這么多屬性,我么要學習哪些屬性呢?
// parentNode 父節點
// childNodes 子節點
?
//獲取父節點
console.log(main.parentNode);
//節點類型 (nodeType) ,如下
// 元素節點 1 屬性節點 2 文本節點 3 注釋節點 8
// 2、獲取所有子節點
console.log(main.childNodes);
// 獲取所有子元素節點
var nodes = main.childNodes;
for (var i = 0; i < nodes.length; i++) {
? ?var node = nodes[i];
? ?//獲取所有元素節點
? ?if (node.nodeType === 1) {
? ? ? ?console.log(node);
? }
}
// 3、有沒有其他更方便的方法獲取到所有子元素節點?
console.log(main.children);//返回 一個Node的所有子元素節點,是一個動態的集(HTMLCollection)
?
~~~
**需求(熟悉)**
隔行變色
目的: 練習children, hasChildNodes()的使用
html和css代碼
~~~
<div>
? ?<ul id="list">
? ? ? ?<li>西施</li>
? ? ? ?<li>昭君</li>
? ? ? ?<li>貂蟬</li>
? ? ? ?<li>玉環</li>
? ? ? ?<li>芙蓉姐姐</li>
? ?</ul>
</div>
~~~
JavaScript代碼
~~~
// 1、以前的方式
// var list = document.getElementsByTagName('li');
?
// 2、現在的方式
//通過子節點完成隔行變色,獲取元素的子節點:
// 方式一:childNodes ? 動態集合
// 方式二:children ? ? 動態集合
var list = document.getElementById('list');
// 判斷是否有子節點(hasChildNodes()),遍歷子元素節點,隔行變色
if (list.hasChildNodes()) {
? ?for (var i = 0; i < list.children.length; i++) {
? ? ? ?var li = list.children[i];
? ? ? ?if (i % 2 === 0) {//奇數行
? ? ? ? ? ?li.style.backgroundColor='lightblue';
? ? ? }else { //偶數行
? ? ? ? ? ?li.style.backgroundColor='lightyellow'
?
? ? ? }
? }
}
~~~
## **第一個和最后一個子節點(掌握)**
獲取第一個和最后一個子節點:
**firstChild 第一個子節點** ?
**lastChild 最后一個子節點**
獲取第一個和最后一個子元素節點: ? firstElementChild:有瀏覽器兼容性問題,從IE9開始支持 ? lastElementChild:有瀏覽器兼容性問題,從IE9開始支持
html和css代碼
~~~
<div id="main">
? ?<div>這是一個廣告圖片</div>
? ?<ul>
? ? ? ?<li>這是一個列表</li>
? ?</ul>
? ?<span>說明性文字</span>
</div>
~~~
JavaScript代碼
~~~
//獲取第一個和最后一個子節點
//firstChild ? 第一個子節點
//lastChild ? ? 最后一個子節點
var main = document.getElementById('main');
console.log(main.firstChild);
?
//獲取第一個和最后一個子元素節點
//firstElementChild:有瀏覽器兼容性問題,從IE9開始支持
//lastElementChild:有瀏覽器兼容性問題,從IE9開始支持
console.log(main.firstElementChild);
console.log(main.lastElementChild);
?
var firstEle = getFirstElementChild(main);
console.log(firstEle);
~~~
**菜單**
目的: 練習parentNode,children,firstElementchild的使用,要理解"先清除后設置"的思想;
需求描述:
點擊菜單時,先清除所有菜單的高亮效果,再設置當前點擊的菜單為高亮顯示。
需求分析:
(1)遍歷li, 給li中的第一個a標簽注冊點擊事件;
(2)先清除所有菜單的高亮效果, 再設置當前點擊的菜單為高亮顯示;
html和css代碼
~~~
<style>
? ?#menu ul li {
? ? ? ?list-style-type: none;
? ? ? ?width: 80px;
? ? ? ?height: 30px;
? ? ? ?line-height: 30px;
? ? ? ?background-color: #595b5d;
? ? ? ?text-align: center;
? ? ? ?float: left;
? ? ? ?margin-left: 5px;
? }
?
? ?#menu ul li.current {
? ? ? ?background-color: thistle;
? }
?
? ?#menu ul li a {
? ? ? ?text-decoration: none;
? ? ? ?color: aliceblue;
? }
?
? ?#menu ul li a:hover {
? ? ? ?color: red;
?
? }
?
? ?/*#menu ul li:hover {*/
? ?/*background-color: aliceblue;*/
? ?/*}*/
</style>
<script src="common.js"></script>
?
<div id="menu">
? ?<ul>
? ? ? ?<li class="current"><a href="javascript:void(0)">首頁</a></li>
? ? ? ?<li><a href="javascript: undefined">叩丁狼</a></li>
? ? ? ?<li><a href="javascript:void(0)">博客</a></li>
? ? ? ?<li><a href="javascript:void(0)">相冊</a></li>
? ? ? ?<li><a href="javascript:void(0)">關于</a></li>
? ? ? ?<li><a href="javascript:void(0)">幫助</a></li>
? ?</ul>
</div>
~~~
JavaScript代碼
~~~
var menu = my$('menu');
//firstChild:獲取第一個節點
//firstElementChild:獲取第一個元素節點
var ul = getFirstElementChild(menu);
//遍歷li中的a標簽,并注冊點擊事件
for (var i = 0; i < ul.children.length; i++) {
? ?var li = ul.children[i];
? ?//獲取a元素節點
? ?var link = getFirstElementChild(li);
? ?link.onclick = linkClick;
}
?
function linkClick() {
? ?//取消所有li的高亮顯示
? ?for (var i = 0; i < ul.children.length; i++) {
? ? ? ?var li = ul.children[i];
? ? ? ?li.className='';
? }
? ?//設置當前點擊的li標簽為高亮顯示
? ?this.parentNode.className = 'current';
}
~~~
**小結**
>[info] 1、認識 javascript:void(0)
> https: 協議
> javascript: 偽協議
> void(0): 運算符,對給定的表達式進行求值,始終返回 undefined。當返回undefined時,a標簽不會做任何事情
> 2、獲取子元素節點、父元素節點、第一個元素節點(解決瀏覽器兼容性問題)
<br>
## 兄弟節點(掌握)
通過DOM文檔樹結構中上下節點是父子關系,水平(同級)節點是兄弟關系,那怎么獲取一個節點的兄弟節點呢? nextSibling 獲取下一個兄弟節點 nextElementSibling 獲取下一個兄弟元素節點 previousSibling 獲取上一個兄弟節點 previousElementSibling 獲取上一個兄弟元素節點 通過以下代碼了解獲取兄弟節點的屬性,以及解決該屬性的瀏覽器兼容性問題。
html和css代碼
~~~
<div id="main">
? ?<div>這是一個區域1</div>
? ?<div>這是一個區域2</div>
? ?<div id="c3">這是一個區域3</div>
? ?<div>這是一個區域4</div>
? ?<div>這是一個區域5</div>
</div>
~~~
JavaScript代碼
~~~
var c3 = document.getElementById('c3');
//獲取兄弟節點
console.log(c3.nextSibling);//獲取上一個兄弟節點
console.log(c3.nextElementSibling);//獲取上一個兄弟元素節點
?
console.log(c3.previousSibling);//獲取下一個兄弟節點
console.log(c3.previousElementSibling);//獲取下一個兄弟元素節點
?
var nextEle = getNextElementSibling(c3);
console.log(nextEle);
?
//解決瀏覽器對nextElementSibling的兼容性問題
function getNextElementSibling(element) {
? ?var el = element;
? ?while (el = el.nextSibling) {
? ? ? ?if (el.nodeType === 1) {
? ? ? ? ? ?return el;
? ? ? }
? }
? ?return null;
}
//同理,用同樣的方式解決瀏覽器對previousElementSibling的兼容性問題
?
~~~
**小結**
>[info] 1. childNodes和children的區別,childNodes獲取的是所有的子節點,children獲取的是子元素節點
> 2. nextSibling和previousSibling獲取的是兄弟節點,nextElementSibling和previousElementSibling獲取的是兄弟元素節點
> 3. nextElementSibling和previousElementSibling有兼容性問題,IE9以后才支持
# **創建元素的三種方式**
**document.write()**:將一個文本字符串寫入到由 document.open() 打開的一個文檔流中;
**innerHTML**:設置或獲取HTML語法表示的元素的后代;
**document.createElement( tagName )**:創建由 tagName 指定的HTML元素;
### document.write()(熟悉)
默認情況之下,頁面由上而下地加載,形成一個文檔流,當執行完畢時,文檔流就會關閉。當使用documen.write()創建元素時,實際是開啟一了個新的文檔流,而將之前文檔流沖刷掉,所以不推薦使用這種方法。
html和css代碼
~~~
<input type="button" id="btn" value="document.write()"/><br><br>
<a id="ibangkf" href="http://www.ibangkf.com">網站客服</a>
<div>
? ?<span>我是span標簽</span>
? ?<b>我是b標簽</b>
</div>
~~~
JavaScript代碼
~~~
my$('btnSet').onclick=function () {
? ?document.write('<p>我是p標簽</p>');
}
~~~
### innerHTML(掌握)
標簽中會插入一個p標簽,并在在頁面上輸出"新標簽",當需要添加的標簽比較多的時候使用這種方式。
html和css代碼
~~~
<input type="button" id="btn" value="innerHTML"/>
<input type="button" id="btnSet" value="生成四大美女"/>
<div id="main">
? ?<span>我是span標簽</span>
</div>
~~~
JavaScript代碼
~~~
//點擊按鈕時,將li標簽加入到ul標簽中,生成美女列表
var array = ['西施', '昭君', '貂蟬', '玉環'];
var main = my$('main');
my$('btnSet').onclick = function () {
? ?main.innerHTML = '<ul>';
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?main.innerHTML += '<li>' + array[i] + '</li>';
? }
? ?main.innerHTML += '</ul>';
}
//問題:每次給innerHTML賦值時,瀏覽器就會重新繪制DOM樹的結構,導致性能降低。
~~~
<br>
## innerHTML性能問題(熟悉)
innerHTML方法由于會對字符串進行解析,需要避免在循環內多次使用。可以借助字符串或數組的方式進行替換,再設置給innerHTML,優化后與document.createElement性能相近。
優化一:使用字符串方式
~~~
var array = ['西施', '昭君', '貂蟬', '玉環'];
var main = my$('main');
//優化一:使用字符串方式
?
my$('btnSet').onclick = function () {
? ?var str += '<ul>';
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?str += '<li>' + array[i] + '</li>';
? }
? ?main.innerHTML = str + '</ul>';
}
~~~
優化二:使用數組方式
~~~
//優化二:使用數組方式
var array = ['西施', '昭君', '貂蟬', '玉環'];
var main = my$('main');
my$('btnSet').onclick = function () {
? ?var strArray = [];
? ?strArray.push('<ul>');
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?strArray.push('<li>' + array[i] + '</li>');
? }
? ?strArray.push('<ul>');
? ?main.innerHTML = strArray.join('');
}
~~~
## document.createElement()(掌握)
在內存中創建一個標簽所對應的DOM對象,當需要動態創建結構比較復雜的標簽時, 可使用這種方式。
html和css代碼
~~~
<input type="button" id="btn1" value="生成四大美女"/><br><br>
<div id="main">
? ?<span>我是span標簽</span>
</div>
~~~
JavaScript代碼
~~~
// 方式三:document.createElement()
//在內存中創建一個p標簽的DOM對象
my$('btnSet').onclick=function () {
? ?var p = document.createElement('p');
? ?p.innerText='我是p標簽';
? ?p.style.backgroundColor='red';
? ?//將p標簽設置到div中,appendChild方法:將子元素設置到當前元素(父元素)的子元素列表中的最后一個位置
? ?my$('main').appendChild(p);
}
~~~
# 節點操作方法介紹
類似于對象屬性的增刪改查,節點中也經常對節點屬性進行增刪改查,這需要用到節點方法,以下介紹常用的節點方法。
createElement(tagName) 創建指定名稱tagName的HTML元素; appendChild(childNode) 將指定的 childNode 參數作為最后一個子節點添加到當前節點,返回 childNode。如果參數引用了 DOM 樹上的現有節點,則節點將從當前位置分離,并附加到新位置;
parentNode.insertBefore(newNode, oldSubNode) 在當前節點之前插入子節點。如果給定的子節點已存在當前文檔中,則insertBefore()會將其從當前位置移動到新位置;
removeChild(child) 從當前節點中刪除指定的子節點child,并返回被刪除的子節點; replaceChild(newChild, oldChild) 在當前節點中,用 newChild 替換 oldChild 并返回被替換掉的 oldChild;
以上節點操作相關的方法,通過下面的需求來練習、熟悉。
# 需求
## 動態創建列表(熟悉)
需求:當點擊按鈕時, 創建美女列表,當鼠標經過列表時,高亮顯示 ; 目的: 練習createElement(), appendChild()方法的使用; 需求分析: (1) 當點擊按鈕時, 使用createElement(),動態生成li ; (2) 動態生成li時, 給每個li注冊鼠標移入移出事件,在事件處理函數中設置li的樣式 ;
html和css代碼
~~~
<input type="button" id="btnSet" value="生成美女列表"/>
<div id="box">
?
</div>
~~~
JavaScript代碼
~~~
//動態創建列表,當鼠標經過列表時,高亮顯示
var array = ['西施', '昭君', '貂蟬', '玉環'];
my$('btnSet').onclick = function () {
? ?var box = my$('box');
? ?var ul = document.createElement('ul');
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?var li = document.createElement('li');
? ? li.innerHTML = array[i];
? ? ? ?//注冊鼠標經過事件
? ? ? ?li.onmouseover = fn1;
? ? ? ?li.onmouseout = fn2;
? ? ? ?//將li添加到ul中
? ? ? ?ul.appendChild(li);
? }
? ?//將ul添加到div中
? ?box.appendChild(ul);
}
?
//獲取頁面中所有的li元素
var list = document.getElementsByTagName('li');
function fn1() {
? ?//設置當前li的背景高亮樣式
? ?this.style.backgroundColor = 'lightblue';
}
function fn2() {
? ?//清空當前li的背景高亮樣式
? ?this.style.backgroundColor = '';
}
~~~
### 動態創建表格(作業)
需求:根據表格數據動態創建表格
1、創建表格 table 設置表格樣式:邊框,邊框間距, 寬高等; 2、創建表頭 thead 將表頭加入到表格中,設置表頭的高,背景顏色;
3、創建表體 tbody (1)創建datas數組對象,用于模擬表格數據; (2)創建行,創建行中的列,并給行中的每列設置值;將每列加入到行中,將每行加入到tbody中;
4、在創建行時, 要在每行的最后一列設置a標簽, 用于刪除操作, 當點擊a標簽時, 刪除當前行;
注意:此案例代碼雖然多,但邏輯簡單,大家只要清楚表格的結構,就很容易寫出相應的代碼。
html和css代碼
~~~
<style>
?#box{
? ?width: 500px;
? ?margin: 0 auto;
}
</style>
?
<div id="box"></div>
~~~
JavaScript代碼
~~~
// 表體數據
var datas = [
{name: '劉備', subject: '語文', score: 80},
{name: '關羽', subject: '語文', score: 90},
{name: '張飛', subject: '語文', score: 50},
{name: '曹操', subject: '語文', score: 100},
{name: '諸葛亮', subject: '語文', score: 100},
]
?
// 表頭數據
var array = ['姓名', '學科', '成績','操作'];
?
// 獲取box盒子
var oDiv = document.getElementById('box');
?
// 創建table并注入到oDiv中
var tableTag = document.createElement('table');
tableTag.style.width = '100%';
tableTag.style.borderCollapse = 'collapse';
oDiv.appendChild(tableTag);
?
/*------------------------為table中寫入(thead>tr>th*3)------------------------*/
// 創建thead
var theadTag = document.createElement('thead');
tableTag.appendChild(theadTag);
?
// 創建thead下的tr
var theadTrTag = document.createElement('tr');
theadTag.appendChild(theadTrTag);
?
// 根據array的個數,創建th
for(var i=0;i<array.length;i++){
?var thTag = document.createElement('th');
?thTag.innerHTML = array[i];
?thTag.style.border = '1px solid #000';
?theadTrTag.appendChild(thTag);
}
?
/*------------------------為table中寫入(tbody>tr>td*3)------------------------*/
// 創建tbody
var tbodyTag = document.createElement('tbody');
tableTag.appendChild(tbodyTag);
?
// 根據datas的個數,創建tbody下的tr
for(var i=0;i<datas.length;i++){
?var myData = datas[i]; ?// 保存數組中每個項
?
?// 創建tbody下的tr
?var tbodyTrTag = document.createElement('tr');
?tbodyTag.appendChild(tbodyTrTag);
?
?for(key in myData){
? ?var tdTag = document.createElement('td');
? ?tdTag.innerHTML = myData[key];
? ?tdTag.style.textAlign = 'center';
? ?tdTag.style.border = '1px solid #000';
? ?tbodyTrTag.appendChild(tdTag);
}
?
?// 添加最后一個刪除按鈕
?var tdTag1 = document.createElement('td');
?var aTag = document.createElement('a');
?aTag.href = 'javascript:void(0);';
?aTag.innerHTML = '刪除';
?tdTag1.appendChild(aTag);
?tdTag1.style.textAlign = 'center';
?tdTag1.style.border = '1px solid #000';
?tbodyTrTag.appendChild(tdTag1);
?
?// 點擊了刪除按鈕
?aTag.onclick = deleteFn;
}
?
// 刪除行
function deleteFn(){
?var trTag = this.parentNode.parentNode;
?tbodyTag.removeChild(trTag);
}
~~~
## 常用DOM方法小結
>[info] createElement()、appendChild()、removeChild()、insertBefore()、replaceChild(),見**節點操作**一節。
>
> 1、var insertedNode = parentNode.insertBefore(newNode, referenceNode);
> 在當前節點中將newNode插入referenceNode之前。如果給定的子節點已存在當前文檔中,則insertBefore()會將其從當前位置移動到新位置;
> ?
> 2、var replacedNode = parentNode.replaceChild(newChild, oldChild);
> 在當前節點中,用 newChild 替換 oldChild 并返回被替換掉的 oldChild;
>
> 3、var childNode = parentNode.appendChild(childNode);
> 將指定的 childNode 參數作為最后一個子節點添加到當前節點,返回 childNode。如果參數引用了 DOM 樹上的現有節點,則節點將從當前位置分離,并附加到新位置;
>
## 選擇水果(掌握)
需求:向左移動全部水果,向左移動選中的水果;向右移動全部水果,向右移動選中的水果;
全部向右移動:獲取左邊所有選項,并加入到右邊的select中。
html和css代碼
~~~
<style>
? ?select {
? ? ? ?width: 200px;
? ? ? ?height: 200px;
? ? ? ?background-color: lightblue;
? ? ? ?font-size: 20px;
? }
</style>
?
<select id="leftSelect" multiple="multiple">
? ?<option>蘋果</option>
? ?<option>橘子</option>
? ?<option>梨</option>
? ?<option>西瓜</option>
? ?<option>水蜜桃</option>
</select>
?
<input type="button" value=">>" id="btn1">
<input type="button" value="<<" id="btn2">
<input type="button" value=">" id="btn3">
<input type="button" value="<" id="btn4">
?
<select id="rightSelect" multiple="multiple">
?
</select>
?
<script src="common.js"></script>
?
~~~
JavaScript代碼
需求分析:
(1)全部向右移動,全部向左移動;
(2)向右移動選中項,向左移動選中項;
~~~
var leftSelect = my$('leftSelect');
var rightSelect = my$('rightSelect');
?
// ==========================全部向右移動============================
my$('btn1').onclick = function () {
? ?//獲取左邊所有選項,并加入到右邊的select中
? ?for (var i = 0; i < leftSelect.children.length; i++) {
? ? ? ?var option = leftSelect[i];
? ? ? ?rightSelect.appendChild(option);
? }
?
}
~~~
以上代碼,正向遍歷,存在問題:每次移除左側選項之后,左側數據索引都要重新排序
~~~
//逆向遍歷
my$('btn1').onclick = function () {
? ?for (var i = leftSelect.children.length-1; i >=0; i--) {
? ? ? ?var option = leftSelect[i];
? ? ? ?rightSelect.appendChild(option);
? }
}
~~~
以上代碼,逆向遍歷,存在問題:選項順序顛倒
~~~
my$('btn1').onclick = function () {
? ?for (var i = 0; i < leftSelect.children.length; i++) {
? ? ? ?var option = leftSelect[0];
? ? ? ?rightSelect.appendChild(option);
? }
}
~~~
以上代碼,只選擇左側下標為0的項,存在問題:i 的值和元素長度是動態變化的,導致i的值不滿足循環條件。
(1)全部向右移動,全部向左移動。 由于select標簽中的option的個數是動態變化的, 最后導致不滿足循環條件了, 針對這個為題, 我們可以先將select中option的個數存儲起來, 將該值當做循環中 i 的范圍, 即var len =leftSelect.children.length, for循環中 i< len ;
參考代碼如下
~~~
// ==========================全部向右移動============================
my$('btn1').onclick = function () {
? ?var len = leftSelect.children.length;
? ?for (var i = 0; i < len; i++) {
? ? ? ?var option = leftSelect.children[0];
? ? ? ?// 將左邊的option追加到右邊select中
? ? ? ?rightSelect.appendChild(option);
? ? ? ?option.selected = false;
? }
}
?
// ==========================全部向左移動============================
?
my$('btn2').onclick = function () {
? ?var len = rightSelect.children.length;
? ?for (var i = 0; i < len; i++) {
? ? ? ?var option = rightSelect.children[0];
? ? ? ?leftSelect.appendChild(option);
? ? ? ?option.selected = false;
? }
}
~~~
(2)向右移動選中項,向左移動選中項。參考代碼如下
需求分析:
a、獲取所有選中的option,存儲到數組中 ? b、遍歷數組,將數組中的option加入到rightSelect中
~~~
// ==========================向右移動選中項============================
//將已選中的option存儲到數組中
my$('btn3').onclick = function () {
? ?var array = [];
? ?var len = leftSelect.children.length;
? ?for (var i = 0; i < len; i++) {
? ? ? ?var option = leftSelect[i];
? ? ? ?if (option.selected) {
? ? ? ? ? ?//將已選中的option加入到數組中
? ? ? ? ? ?array.push(option);
? ? ? ? ? ?//取消option的選中狀態
? ? ? ? ? ?option.selected = false;
? ? ? }
? }
?
? ?//將數組中(即已選中的option)的option移動到rightSelect中
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?var option = array[i];
? ? ? ?rightSelect.appendChild(option);
? }
}
?
?
// ==========================向左移動選中項============================
?
my$('btn4').onclick = function () {
? ?var array = [];
? ?var len = rightSelect.children.length;
? ?for (var i = 0; i < len; i++) {
? ? ? ?var option = rightSelect[i];
? ? ? ?if (option.selected) {
? ? ? ? ? ?//將已選中的option加入到數組中
? ? ? ? ? ?array.push(option);
? ? ? ? ? ?//取消option的選中狀態
? ? ? ? ? ?option.selected = false;
? ? ? }
? }
?
? ?//將數組中(即已選中的option)的option移動到rightSelect中
? ?for (var i = 0; i < array.length; i++) {
? ? ? ?var option = array[i];
? ? ? ?leftSelect.appendChild(option);
? }
}
~~~
## innerHTML實現選擇水果(了解)
使用innerHTML實現選擇水果的功能,存在以下的問題。
~~~
//使用innerHTML實現
rightSelect.innerHTML = leftSelect.innerHTML;
//清空做左邊的選項
leftSelect.innerHTML = '';
?
//存在的問題
// 1、如果子元素中注冊了事件,則在移動子元素之后,子元素中的事件丟失。
// 2、使用leftSelect.innerHTML = '' 清空子元素之后,如果子元素中注冊了事件,則事件仍然存在內存中,即此時發生內存泄漏。
~~~
## DOM對象總結
~~~
================================= 知識點總結 =================================
?
~~~