DOM: Document Object Model(文檔對象模型)
DOM樹:

回流和重繪
重繪(repaint):
當(dāng)元素樣式的改變不影響布局時,瀏覽器將使用重繪對元素進(jìn)行更新,此時由于只需要 UI 層面的重新像素繪制,因此損耗較少。
常見的重繪操作有:
改變元素顏色
改變元素背景色
more ……
回流(reflow):
又叫重排(layout)。當(dāng)元素的尺寸、結(jié)構(gòu)或者觸發(fā)某些屬性時,瀏覽器會重新渲染頁面,稱為回流。此時,瀏覽器需要重新經(jīng)過計算,計算后還需要重新頁面布局,因此是較重的操作。
常見的回流操作有:
頁面初次渲染
瀏覽器窗口大小改變
元素尺寸/位置/內(nèi)容發(fā)生改變
元素字體大小變化
添加或者刪除可見的 DOM 元素
……
重點:回流必定會觸發(fā)重繪,重繪不一定會觸發(fā)回流。重繪的開銷較小,回流的代價較高。
DOM 操作
1、獲取元素
1.1 根據(jù)id名獲取
document.getElementById(idName)
1.2 根據(jù)標(biāo)簽名獲取
document.getElementsByTagName(tagName)? // 返回一個集合 (類數(shù)組對象)? 從整個文檔獲取
element.getElementsByTagName(tagName)? ? // 從element的后代元素中獲取
1.3 根據(jù)類名獲?。ú患嫒輎e6~8)
document.getElementsByClassName(className)? // 返回一個集合(類數(shù)組對象)? 從整個文檔獲取
element.getElementsByClassName(className)? // 從element的后代中獲取
1.4 根據(jù) name 屬性值獲取
正常的規(guī)范中,咱們只會給表單元素起name值,如果給其它元素設(shè)置name,在ie9以下版本瀏覽器不兼容,是獲取不到的,
所以為了這種情況,咱們以后養(yǎng)成習(xí)慣,只給表單元素用name,非表單元素不用name
document.getElementsByName()? //返回集合? 只有document才有該方法
1.5 根據(jù)選擇器獲取
注意:querySelector 和querySelectorAll 在ie6-ie8 下不兼容
document.querySelector(選擇器)? //選擇器第一個滿足選擇器條件的
document.querySelectorAll(選擇器) //選擇所有滿足選擇器條件的,返回nodeList(類數(shù)組對象)
element.querySelector(選擇器)
element.querySelectorAll(選擇器)
1.6 document.head?
? ? ? 獲取Head元素對象
1.7? document.body
? ? 獲取body元素對象
1.8 document.documentElement
? ?獲取html元素對象
2、獲取一屏幕的寬度或者高度,兼容所有的瀏覽器
// 獲取一屏幕的高度
varvH=document.documentElement.clientHeight||document.body.clientHeight;
// 偶去一屏幕的寬度
varvW=document.documentElement.clientWidth||document.body.clientWidth;
3、id小妙招?直接把id當(dāng)成變量去用的時候,可以獲取相應(yīng)的id元素。(瀏覽器的機(jī)制)
<script>
console.log(box1)
</script>
2、節(jié)點
●文檔節(jié)點●屬性節(jié)點●元素節(jié)點●文本節(jié)點●注釋節(jié)點
2.1 文檔節(jié)點
●nodeType(節(jié)點類型):9●nodeName(節(jié)點名稱):"#document"●nodeValue(節(jié)點值):null
document.nodeType;
document.nodeName
document.nodeValue;
2.2 屬性節(jié)點
●nodeType:2●nodeName:屬性名●nodeValue:屬性值getAttributeNode() 方法從當(dāng)前元素中通過名稱獲取屬性節(jié)點。
vara1=a1.getAttributeNode("href");// 獲取屬性節(jié)點
console.log(a1.nodeType);//2
console.log(a1.nodeName);//"href"; 屬性名
console.log(a1.nodeValue);//"http://www.baidu.com"; 屬性值

2.3 元素節(jié)點
●nodeType:1●nodeName:大寫的標(biāo)簽名●nodeValue:null
<script>
console.log(box.nodeName)
</script>
2.4 文本節(jié)點
●nodeType:3●nodeName:"#text"●nodeValue:文本內(nèi)容●在標(biāo)準(zhǔn)瀏覽器中,換行和空格也屬于文本節(jié)點
varres=a1.childNodes[0];
console.log(res.nodeType);//3
console.log(res.nodeValue);//"百度";
console.log(res.nodeName);//"#text";
2.5 注釋節(jié)點
●nodeType:8●nodeName:"#comment"●nodeValue:注釋的內(nèi)容
<!--a標(biāo)簽-->
百度
</a>
a1.childNodes;//NodeList(3)?[text, comment, text]
a1.childNodes[1].nodeName;//"#comment"
a1.childNodes[1].nodeType;//8
a1.childNodes[1].nodeValue;//"a標(biāo)簽 "
3、節(jié)點之間關(guān)系的屬性
節(jié)點類:
parentNode? ? 父節(jié)點
childNodes? ? 所有子節(jié)點的集合
firstChild? ? 第一個子節(jié)點
lastChild? ? 最后一個子節(jié)點
previousSibling? 上一個兄弟節(jié)點
nextSibling? ? ? 下一個兄弟節(jié)點
元素類:
children? ? 所有子元素的集合
firstElementChild? 第一個子元素? IE9+
lastElementChild? ? 最后一個子元素 IE9+
previousElementSibling? 上一個兄弟元素 IE9+
nextElementSibling? ? 下一個兄弟元素? IE9+
3.1 parentNode獲取當(dāng)前節(jié)點唯一的父親節(jié)點
<div>
<!--111-->
<div id="box">111</div>
</div>
</div>
<script>
console.log(box.parentNode)
</script>
3.2 childNodes獲取當(dāng)前節(jié)點所有的子節(jié)點
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<script>
console.log(main.childNodes);//NodeList(11)?[text, comment, text, li, text, li, text, li, text, li, text]
3.3 firstChild獲取被選節(jié)點的第一個子節(jié)點。
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<script>
console.log(main.firstChild);//#text
3.4 lastChild獲取被選節(jié)點的最后一個子節(jié)點。
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<script>
console.log(main.lastChild);//#text
3.5 previousSibling獲取上一個哥哥節(jié)點
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<script>
console.log(main.previousSibling);//#text
3.6 nextSibling獲取當(dāng)前節(jié)點的下一個兄弟節(jié)點
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul><!-- 1111 -->
<script>
console.log(main.nextSibling);//<!-- 1111 -->
3.7 children獲取當(dāng)前元素所有的元素子節(jié)點,但是在ie6--ie8下不兼容3.8 firstElementChild獲取當(dāng)前節(jié)點的第一個元素子節(jié)點 ie6-ie8 不兼容
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<script>
console.log(main.firstElementChild);
3.9 lastElementChild獲取當(dāng)前節(jié)點的最后一個元素子節(jié)點? ie6-ie8 不兼容
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!111</li>
</ul>
<script>
console.log(main.lastElementChild);
3.10 previousElementSibling獲取上一個哥哥元素節(jié)點? ie6-ie8 不兼容<ul id="main">
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!111</li>
</ul>
<script>
console.log(main.previousElementSibling);
3.11 nextElementSibling獲取當(dāng)前節(jié)點的下一個兄弟元素節(jié)點? ? ie6-ie8 不兼容
<ul id="main">
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!111</li>
</ul>
<script>
console.log(main.nextElementSibling);
練習(xí)題
自己手動封裝一個獲取節(jié)點下面的所有子元素,要求考慮兼容性。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
<style>
</style>
</head>
<body>
<span id="span1">1</span>
<ul id="main">
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<span>2</span>
</body>
</html>
<script>
functionchildren(element){
varnodeLists=element.childNodes;
varresult=[]
for(vari=0;i<nodeLists.length;i++){
nodeLists[i].nodeType===1?result.push(nodeLists[i]):null;
}
returnresult;
}
console.log(children(main));
自己手動封裝一個previousElementSibling,要兼容。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
<style>
</style>
</head>
<body>
<span id="span1">1</span>
<ul id="main">
<!--我是注釋-->
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
<li>選擇珠峰的,都是明智的!</li>
</ul>
<span id="span2">2</span>
</body>
</html>
<script>
functionpreviousElmentSibling(ele){
varpre=ele.previousSibling;
while(pre&&pre.nodeType!==1){
pre=pre.previousSibling;
}
returnpre;
}
console.log(previousElmentSibling(span2))
</script>
DOM 的增刪改
1、createElement:創(chuàng)建一個元素
document.createElement("div");
2、createTextNode: 創(chuàng)建一個文本節(jié)點
var otext=document.createTextNode("哈哈!");
3、appendChild:把元素追加到一個容器的末尾
語法:[context].appendChild([元素]);
<div id="id1"></div>
? <script>
? ? var odiv = document.createElement("div");
? ? id1.appendChild(odiv);
? ? console.log(id1)
? </script>
4、insertBefore: 把一個元素插入到另一個元素的前面
首先要指定一個父節(jié)點
var? insertedNode = 父節(jié)點.insertBefore(要插入的節(jié)點, 插在這個節(jié)點之前)
var? insertedNode = parentNode.insertBefore(newNode, referenceNode)
newNode:將要插入的節(jié)點
referenceNode:被參照的節(jié)點(即要插在該節(jié)點之前)
insertedNode:插入后的節(jié)點
parentNode:父節(jié)點
<div id="id1">
? <p class="p1" id="p1">這是P1</p>
</div>
<script>
? var div = document.getElementById('id1');
? var p1 = document.getElementById('p1');
? var odiv = document.createElement("div");
? var returnDom = div.insertBefore(odiv, p1);
console.log(div)
</script>
5、cloneNode:把某一個節(jié)點進(jìn)行克隆
【ele】.cloneNode();淺克?。?只是克隆了一個節(jié)點,里面的內(nèi)容還有樣式都沒克隆
【ele】.cloneNode(true);深克隆:把節(jié)點包含的所有內(nèi)容進(jìn)行克隆
<div id="id1">
? ? <p class="p1" id="p1">這是P1</p>
? </div>
? <script>
? ? var res = id1.cloneNode();
? ? var res2 = id1.cloneNode(true)
? ? console.log(res)
? ? console.log(res2)
? </script>
6、removeChild:移除某個節(jié)點
【context】.removeChild(ele);
<div id="id1">
? ? 1111
? ? <p class="p1" id="p1">這是P1</p>
? </div>
? <script>
? ? id1.removeChild(p1);
? ? console.log(id1)
? </script>
7、set/get/removeAttribute
設(shè)置/獲取/刪除 當(dāng)前元素的某一個自定義屬性
setAttribute
getAttribute
removeAttribute
box.setAttribute("index", 1);
box.getAttribute("index");
box.removeAttribute("index");
console.log(box)
// 設(shè)置
// box["aa"] = 22;
// 獲取
// box["aa"]
//移除
// delete box["aa"];
基于鍵值對方式 增刪改:修改當(dāng)前對象的堆內(nèi)存空間完成的(在堆內(nèi)存空間可以看到)
基于Attribute dom方法增刪改,是修改html結(jié)構(gòu)來完成的(此種方法設(shè)置的在結(jié)構(gòu)上可以看到)
以上兩種方式不能混用
題目
利用a標(biāo)簽的href來重新獲取url參數(shù)
var str = "http://www.zhufengpeixun.cn?name=lili&age=18#123"

<!DOCTYPE html>
<html lang="en">
<head>
? <meta charset="UTF-8">
? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? <title>Document</title>
</head>
<body>
? <script>
? ? var str = "http://www.zhufengpeixun.cn?name=lili&age=18#123"
? ? /*
? ? search: "?name=lili&age=18"
? ? hash: "#123"
? ? */
? ? function queryParams(str) {
? ? ? var a = document.createElement("a");
? ? ? a.href = str;
? ? ? var obj = {};
? ? ? console.log(a.search); //?name=lili&age=18
? ? ? console.log(a.hash); //#123
? ? ? //[name=lili,age=18]
? ? ? var search = a.search.substr(1);
? ? ? console.log(search);//name=lili&age=18
? ? ? obj.hash = a.hash ? a.hash : null;
? ? ? if (search) {
? ? ? ? var searchAry = search.split("&");
? ? ? ? console.log(searchAry)//?['name=lili', 'age=18']
? ? ? ? for (var i = 0; i < searchAry.length; i++) {
? ? ? ? ? var itemAry = searchAry[i];//name=lili? age=18
? ? ? ? ? var item = itemAry.split("=");
? ? ? ? ? console.log(item)//['name', 'lili']['age', '18']
? ? ? ? ? var key = item[0];
? ? ? ? ? var value = item[1];
? ? ? ? ? obj[key] = value;
? ? ? ? }
? ? ? }
? ? ? return obj;
? ? }
? ? var dd = queryParams(str);
? ? console.log(dd)
? </script>
</body>
</html>
1、時間對象
1.1【作用】:Date 對象用于處理日期和時間。
1.2【創(chuàng)建時間對象】: new Date()獲取系統(tǒng)當(dāng)前時間
var myDate=new Date(); //Tue Dec 24 2019 20:44:00 GMT+0800 (中國標(biāo)準(zhǔn)時間);
typeof myDate;====>"object"? // 獲取到是一個對象,并不是字符串
1.3 時間對象相關(guān)屬性和方法
●getFullYear();獲取年●getMonth();獲取月 0到11 代表1月到12月●getDate();獲取日期●getDay();星期幾 (0---6)代表周日到到周六●getHours();時●getMinutes();分●getSeconds();秒●getMilliseconds();毫秒●getTime();獲取當(dāng)前日期到1970年1月1號 00:00:00 之間的毫秒差●toLocaleString();// 獲取到的是年月日,時分秒"2019/12/25 上午10:15:50"●toLocaleDateString();//? 獲取到是字符串的年月日,例如:"2019/12/25"●toLocaleTimeString();/ 獲取到的是字符串的時分秒上午10:18:28
2、案例:鐘表
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
<style>
#clock{
height:50px;
line-height:50px;
text-align:center;
}
</head>
<body>
<div class="clock"id="clock">
</div>
<script>
functionclock(){
vartime=newDate;
varyear=time.getFullYear();
varmonth=time.getMonth()+1;//0-11 代表1月到12月
vardate=time.getDate();//日期
varday=time.getDay();//0-6代表周日到到六
varhours=time.getHours();
varminutes=time.getMinutes();
varseconds=time.getSeconds();
varweekStr=["日","一","二","三","四","五","六"];
varweek=weekStr[day];
varresult=year+"年"+month+"月"+date+"日"+"周"+week;
result+=hours+"時"+minutes+"分"+seconds+"秒";
returnresult;
}
vartime=clock();
document.getElementById("clock").innerHTML=time;
setInterval(function(){
vartime=clock();
document.getElementById("clock").innerHTML=time;
},1000)
</script>
</body>
</html>
補(bǔ)0操作:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
<style>
#clock{
height:50px;
line-height:50px;
text-align:center;
}
</head>
<body>
<div class="clock"id="clock">
</div>
<script>
varclock=document.getElementById("clock");
functiongetTime(){
vartime=newDate();
varyear=time.getFullYear();
varmonth=time.getMonth()+1;
vardate=time.getDate();
varday=time.getDay();
varhour=time.getHours();
varminutes=time.getMinutes();
varseconds=time.getSeconds();
varweek=["周日","周一","周二","周三","周四","周五","周六"];
varres=year+"年"+addZero(month)+"月"+addZero(date)+"日"+week[day]+" "+addZero(hour)+":"+addZero(minutes)+":"+addZero(seconds);
returnres;
}
functionaddZero(num){
returnnum<10?"0"+num:num;
}
varres=getTime();
clock.innerText=res;
setInterval(function(){
varres=getTime();
clock.innerText=res;
},1000)
</script>
</body>
</html>
3、定時器:
3.1、setTimeOut? ?
??一定的時間后,去執(zhí)行某些事情,是單次調(diào)用
setTimeout(function(){
? ? alert("wasai!you are beautiful");
},1000)
3.2、setInterval
間隔多少時間后,去執(zhí)行某些事情,是多次調(diào)用
setInterval(function(){
console.log("我真美!")
},1000)
3.3、定時器的參數(shù)說明
// 定時器可以傳遞多個參數(shù):
// 1、執(zhí)行的函數(shù)
// 2、時間
// 3、后面的參數(shù)就是執(zhí)行函數(shù)在執(zhí)行的時候傳遞的實參
setTimeout(function(num,s,m){
console.log(num,s,m);
},1000,2,3,6);
3.4、定時器是有返回值的,返回值代表定時器處于當(dāng)前頁面中的第幾個
vartime1=setTimeout(function(){
console.log("wasai!you are beautiful");
},1000)
vartime2=setInterval(function(){
console.log("我真美!")
},1000)
vartime3=setTimeout(function(){
console.log("aa");
},1000)
console.log(time1)=====>1
console.log(time1)=====>2
console.log(time1)=====>3
3.5、定時器是異步任務(wù),只要當(dāng)咱們同步代碼執(zhí)行完畢之后,才能執(zhí)行。
setTimeout(function(){
console.log("定時器");
},1000)
console.log("haha")
4、清除定時器的方法
●clearTimeout●clearInterval
5、練習(xí)
做一個抽獎程序,頁面中有一個區(qū)域顯示中獎人員的編號,在JS中寫一段代碼,要求每隔1秒中隨機(jī)創(chuàng)建一個四位的數(shù)字(每一位數(shù)字的取值范圍0-9),當(dāng)10秒結(jié)束后,結(jié)束定時器,最后顯示的四位數(shù)字即是中獎的號碼
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>中獎</title>
? ? <style>
? ? #prize{
? ? ? ? width:200px;
? ? ? ? height:50px;
? ? ? ? border:1px solid green;
? ? }
? ? </style>
</head>
<body>
? ? <div class="prize" id="prize"></div>
</body>
</html>
<script>
? ? function getCode(){
? ? ? ? var str="0123456789";
? ? ? ? var result="";
? ? ? ? for(var i=0;i<4;i++){
? ? ? ? ? ? var index=Math.floor(Math.random()*9);
? ? ? ? ? ? result+=str[index];
? ? ? ? }
? ? ? prize.innerHTML=result;
? ? ? return result;
? ? }
? ? var time1=setInterval(function(){
? ? ? ? getCode();
? ? },1000);
? ? setTimeout(function(){
? ? ? ? clearInterval(time1);
? ? },10000)
</script>
倒計時案例:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible"content="ie=edge">
<title>Document</title>
<style>
*{
margin:0;
padding:0;
}
body {
background:darkslateblue;
}
#time{
height:100px;
line-height:100px;
border:1px dashed yellow;
text-align:center;
color:#fff;
font-size:26px;
}
</head>
<body>
<div id="time">
</div>
<script>
/*
? ? ? 倒計時:
? ? ? 目標(biāo)時間:2021年12月14號
? ? ? 目標(biāo)時間-現(xiàn)在的時候=還剩多少時間?
? ? ? 為了方便計算時間差,我們統(tǒng)一轉(zhuǎn)成到1970年...的時間戳
? ? */
functioncountDown(targetStr){
// 目標(biāo)時間
vartargetTime=newDate(targetStr);
// 現(xiàn)在的時間
varnowTime=newDate()
// 時間差,得出來的是毫秒
vardiffTime=targetTime-nowTime;
// 把時間差換算成時、分、秒
varhours=Math.floor(diffTime/(1000*60*60));
varminutes=Math.floor((diffTime-hours*1000*60*60)/(1000*60));
varseconds=Math.floor((diffTime-hours*1000*60*60-minutes*60*1000)/1000);
varresult=formatter(hours)+"時"+formatter(minutes)+"分"+formatter(seconds)+"秒";
returnresult;
}
functionformatter(val){
returnval=Number(val)<10?"0"+val:val;
}
varres=countDown("2021-12-24 00:00:00");
time.innerHTML=res;
console.log(res)
setInterval(()=>{
varres=countDown("2021-12-24 00:00:00");
time.innerHTML=res;
},1000);
</body>
</html>