一、DOM
1、定義
DOM,即文檔對象模型(Document Object Model )
2、現(xiàn)象
通過在頁面——打開:檢查元素——看見:元素為可折疊??蛇x中頁面對應(yīng)元素,事實(shí)上即選擇了對象(即也選擇了對象對應(yīng)的屬性或方法),相當(dāng)于把頁面文檔對象化。事實(shí)上,就是用js手段調(diào)用操作該文檔(即一個對象)。
二、Document對象,屬性(或方法)
在DOM中最常用的對象就是:document對象(頁面——檢查,即查看屬性)、element對象
1、常用屬性
document.doctype
document.title
document.characterSet
document.head
document.body
document.images
2、document.readyState
document.readyState
readyState屬性 返回當(dāng)前文檔的狀態(tài),共有三種可能的值:
- loading:加載HTML代碼階段,尚未完成解析
- interactive:加載外部資源階段
-
complete:全部加載完成
圖:可在代碼中加上幾張圖片元素,再設(shè)置網(wǎng)絡(luò)條件為慢3G,則出現(xiàn):
image
3、 document.compatMode
document.compatMode
compatMode 屬性 返回瀏覽器處理文檔的模式,可能的值為
- BackCompat:向后兼容模式,也就是沒有添加DOCTYPE
- CSS1Compat:嚴(yán)格模式,添加了DOCTYPE
4、document.location
用于獲取一個url
document.location
可直接使用location,如:
document.location === location //true
document.location === window.location //true
總結(jié):document.location === location === window.location
location屬性返回一個只讀對象,提供了當(dāng)前文檔的URL信息,如:
// 假定當(dāng)前網(wǎng)址為http://user:passwd@www.example.com:4097/path/a.html?x=111#part1
document.location.href // "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
document.location.protocol // "http:"
document.location.host // "www.example.com:4097"
document.location.hostname // "www.example.com"
document.location.port // "4097"
document.location.pathname // "/path/a.html"
document.location.search // "?x=111"
document.location.hash // "#part1"
document.location.user // "user"
document.location.password // "passed"
其他location屬性調(diào)用方法:
// 跳轉(zhuǎn)到另一個網(wǎng)址
document.location.assign('http://www.google.com')
// 優(yōu)先從服務(wù)器重新加載
document.location.reload(true)
// 優(yōu)先從本地緩存重新加載(默認(rèn)值)
document.location.reload(false)
// 跳轉(zhuǎn)到另一個網(wǎng)址,但當(dāng)前文檔不保留在history對象中,
// 即無法用后退按鈕,回到當(dāng)前文檔
document.location.assign('http://www.google.com')
// 將location對象轉(zhuǎn)為字符串,等價(jià)于document.location.href
document.location.toString()
5、document.write( )
用document.write( )方法時,即向當(dāng)前文檔寫入內(nèi)容,只要當(dāng)前文檔還沒有用close方法關(guān)閉,它所寫入的內(nèi)容就會追加在已有內(nèi)容的后面。
1
- 如果頁面已經(jīng)渲染完成再調(diào)用write方法,它會先調(diào)用open方法,擦除當(dāng)前文檔所有內(nèi)容,然后再寫入。
- 如果在頁面渲染過程中調(diào)用write方法,并不會調(diào)用open方法。
-需要注意的是,雖然調(diào)用close方法之后,無法再用write方法寫入內(nèi)容,但這時當(dāng)前頁面的其他DOM節(jié)點(diǎn)還是會繼續(xù)加載。
-做測試時,無須使用document.write( )方法
三、Element對象,屬性(或方法)
document對應(yīng)的具體元素應(yīng)如何選?。ɑ虿僮鳎?br>
element對象表示頁面上的元素。使用JS選擇頁面上的元素(element),然后對其做操作。
那么,對頁面元素的操作有哪些?
A、選擇它:通過一些方法找到其具體元素(如用css的id,class名,選擇器、鄰居、賦值等)
B、處理它:對擁有類型為元素節(jié)點(diǎn)、文本節(jié)點(diǎn)、注釋節(jié)點(diǎn)的子節(jié)點(diǎn)進(jìn)行刪除、增加、查找、修改等操作
1、幾個常用屬性
nodeName:元素標(biāo)簽名,還有個類似的tagName
nodeType:元素類型
className:類名
id:元素id
children:子元素列表(HTMLCollection)
childNodes:子元素列表(NodeList)
firstChild:第一個子元素
lastChild:最后一個子元素
nextSibling:下一個兄弟元素
previousSibling:上一個兄弟元素
parentNode、parentElement:父元素
2、查詢元素(如何選中一個元素?)
(1)getElementById()
結(jié)合頁面元素使用 +
document.getElementByid()
如圖:利用此方法選中該id的頁面位置
(2)getElementsByClassName( ) 注:有s
document.getElementByClassName()
頁面元素中不止獨(dú)一無二的id名,還有類選擇器,當(dāng)我們在頁面控制臺上通過getElementByClassName( )時,可獲?。ɑ虿樵儯┑揭粋€或多個類選擇器,會出現(xiàn)如圖現(xiàn)象:
這看上去有點(diǎn)像數(shù)組,呈現(xiàn)形式相似、也可以用下標(biāo)去進(jìn)行訪問。但通過list.去查看,并沒有有關(guān)排序、push、pop等的調(diào)用數(shù)組的方法,而是一種類數(shù)組的形式。
通過:
list.constructor
--> ? HTMLCollection() { [native code] }
我們可以獲知,document.getElementsByClassName() 所調(diào)用的是html里類的集合,其類型為 HTMLCollection(),是一種頁面元素的集合。
(3)getElementsByName()
document.getElementsByName()
通過此方法可以獲取頁面元素中帶有name屬性的html元素。比如form、img、frame、embed和object,返回一個NodeList格式的對象,不會實(shí)時反映元素的變化。如:
(4)假設(shè),類選擇器有嵌套的話,我們?nèi)绾潍@取嵌套于內(nèi)的元素?如圖:
A、(較為繁瑣的) ES3寫法:getElementsByName( ).getElementsByName( )
語法:
document.getElementsByName().getElementsByName()
例子:
document.getElementsByClassName('box')[0].getElementsByClassName('child')
--> HTMLCollection [div.child]
事實(shí)上,使用document.getElementsByName()做一個聯(lián)集,即無論是document還是任何一個對象,都可以使用:對象.XXXX 去做一個聯(lián)集對象去獲取相對應(yīng)的準(zhǔn)確元素。
B、(較為簡便的)ES5寫法:querySelector()
注:可用于選擇id元素使用
語法:
document.querySelector()
例子:
document.querySelector('.box .child')
--> <div class="child">child</div>
不過,它選擇元素的時候,只能獲取一個元素,如頁面元素中有多個div,只會默認(rèn)選擇html元素中排在第一個的div元素。
如果需要在選擇元素時,多種頁面元素希望可以同時選中,則可以使用
這樣的寫法:querySelectorAll()
注:可用于選擇class元素時使用
例子:
//比如:
document.querySelectorAll('div')
--> NodeList(3) [div.box, div.child, div.box]
document.querySelectorAll('.box')
--> NodeList(2) [div.box, div.box]
document.querySelectorAll('#target')
--> NodeList [p#target]
在控制臺測試時,我們可以直接使用 ()** 和 ** 和 $$() 直接代document.querySelector()和document.querySelectorAll()
$('#target')
--> <p id="target">wangxiaoqin</p>
$$('#target')
--> [p#target]
可以自己寫個方法,讓 $() 和 $$() 可以在代碼編輯器中直接使用,如下:
//寫個方法:
function $(selector){
return document.querySelector(selector)
}
--> undefined
//即下面就可以在編輯器大膽使用$() 和 $$(),舉幾個例子:
$('#target')
--> <p id="target">wangxiaoqin</p>
$('.box')
--> <div class="box">…</div>
$('.box .child')
--> <div class="child">child</div>
(5)getElementsByTagName()
document.getElementsByTagName()
此方法返回所有指定標(biāo)簽的元素(搜索范圍包括本身),返回值是一個HTMLCollection對象,也就是說,搜索結(jié)果是一個動態(tài)集合,任何元素的變化都會實(shí)時反映在返回的集合中。如圖:
3、創(chuàng)建元素
(1)createElement() 創(chuàng)建一個新的元素放到頁面上
用此方法創(chuàng)建并傳入html的元素標(biāo)簽,創(chuàng)建一個虛擬的dom。該dom的節(jié)點(diǎn)存在內(nèi)存里,并沒有放在頁面上,用戶看不見。
如:
document.createElement('div')
--> <div></div>
//可賦值一個變量,之后可通過該變量輕松獲取
var div = document.createElement('div')
--> undefined
div
--> <div></div>
var div = document.createElement('img')
--> undefined
div
--> <img>
(2)createTextNode()
光出現(xiàn)元素標(biāo)簽還不夠,我們可通過createTextNode( )去創(chuàng)建(或生成)一個文本,將文本的內(nèi)容放入元素中,如:
var text = document.createTextNode('wangxiaoqin')
--> undefined
text
--> "wangxiaoqin"
(3)createDocumentFragment()
該方法用來生成一個存在于內(nèi)存的dom片段,但不屬于當(dāng)前文檔。即不會生成一個標(biāo)簽,虛擬生成,常用于生成復(fù)雜的dom結(jié)構(gòu),然后插入當(dāng)前文檔。
正因?yàn)樗粚儆诋?dāng)前文檔,所以并不參與頁面的渲染加載的過程,它的任何改動都不會引發(fā)網(wǎng)頁的重新渲染。比直接修改當(dāng)前文檔的DOM有更好的性能表現(xiàn)。
4、修改元素
(1)appendChild()
在元素末尾添加元素。把一個dom對象放入在另外一個對象的內(nèi)部作為它的孩子
如:
var newDiv = document.createElement("div")
var newContent = document.createTextNode("Hello")
newDiv.appendChild(newContent)//括號內(nèi)為新添加的“孩子”
--> "hello"
看一個實(shí)例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<ul class="navbar"></ul>
</body>
</html>
<script>
//選擇該容器ul,獲取指定元素
var navbarNode = document.querySelector('.navbar')
for(var i=0;i<5;i++){//以下循環(huán)5此
//創(chuàng)建一個子元素li
var child = document.createElement('li')
//創(chuàng)建一個文本,參數(shù)為字符串
var text = document.createTextNode('hello'+i)
//修改元素
child.appendChild(text)
//然后再把li放在我們的navbarNode里
navbarNode.append(child)
}
</script>
如圖:
另一種方法:使用appendChild()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<ul class="navbar"></ul>
</body>
</html>
<script>
//選擇該容器ul,獲取指定元素
var navbarNode = document.querySelector('.navbar')
//創(chuàng)建一個虛擬的片段,可看成是一個虛擬標(biāo)簽,到最后放在navbarNode,該虛擬標(biāo)簽消失
var fragment =document.createDocumentFragment()
for(var i=0;i<5;i++){//以下循環(huán)5此
//創(chuàng)建一個子元素li
var child = document.createElement('li')
//創(chuàng)建一個文本,參數(shù)為字符串
var text = document.createTextNode('helloo'+i)
//修改元素
child.appendChild(text)
//然后再把li放在我們的frgment這個虛擬片段里
fragment.appendChild(child)
}
//再將這個片段放在navbarNode里
navbarNode.appendChild(fragment)
</script>
如圖:
在控制臺我們可以看到:
再回看JS代碼,則可以知道,
var fragment =document.createDocumentFragment()
這里創(chuàng)建的這個虛擬片段,我們可看成是一個虛擬標(biāo)簽,到最后放在navbarNode,該虛擬標(biāo)簽消失。并不影響實(shí)際頁面元素的改動。
假設(shè):我們在createDocumentFragment() 里加上一個實(shí)際的塊元素包裹li,那么則不符合頁面的規(guī)則,如:
控制臺則如:這顯然不符合規(guī)則
(2)insertBefore()
在某個元素之前插入元素
var newDiv = document.createElement("div")
var newContent = document.createTextNode("Hello")
newDiv.insertBefore(newContent, newDiv.firstChild)
(3)replaceChild()
replaceChild( )接受兩個參數(shù):要插入的元素和要替換的元素
newDiv.replaceChild(newElement, oldElement)
5、刪除元素
removeChild() 用于刪除元素
parentNode.removeChild(childNode)
6、clone元素
克隆一個完成的dom節(jié)點(diǎn)。
方法有一個布爾值參數(shù),傳入true的時候會深復(fù)制,也就是會復(fù)制元素及其子元素(IE還會復(fù)制其事件),false的時候只復(fù)制元素本身
node.cloneNode(true)
四、屬性的操作(即修改dom元素的屬性的操作方法)
1、getAttribute()
(現(xiàn)有頁面中有一個圖片地址,所對應(yīng)的是一個src的地址,如果更換圖片,則需要修改src對應(yīng)的值。(或獲取一個img的src,或a鏈接的href))
用于獲取元素的屬性值,如:
node.getAttribute('id')
2、createAttribute() 【一般用不到,一般不創(chuàng)建】
用于創(chuàng)建(或獲?。傩悦?,如
attribute = document.createAttribute(name)//參數(shù)name,是屬性的名稱
3、setAttribute()
用于設(shè)置屬性和值
var node = document.getElementById("div1");
node.setAttribute("my_attrib", "newVal"); //括號中為“屬性名+值”
4、removeAttribute()
用于刪除對應(yīng)屬性
node.removeAttribute('id')
頁面范例展示涉及到的點(diǎn):
(1)查找、修改、獲取、刪除a鏈接的屬性(這里為id)
var link = document.querySelector('a')
link
<a href="#">wanxgiaoqin</a>
//可以創(chuàng)建 a鏈接的id屬性值
link.setAttribute('id','login')
//以此類推,可以修改它的id
link.setAttribute('id','logout')
//可以獲?。ɑ蛱砑樱┧膇d
link.getAttribute('id')
//可以刪除它的id
link.removeAttribute('id')
圖:
(2)創(chuàng)建一個樣式放在頁面上,如何操作?
如:使用js讓我們的頁面上引入一個新的js,如jquery??上仍?a target="_blank" rel="nofollow">Bootstrap 中文網(wǎng)開源項(xiàng)目免費(fèi) CDN 加速服務(wù)上找一個jquery的地址
分析:用js引用一個jQuery,那么需要有一個scirpt的標(biāo)簽,用src來指向jQuery地址
//創(chuàng)建一個script標(biāo)簽
var script = document.createElement('script')
--> undefined
script
<script></script >
//設(shè)置元素的屬性和值
script .setAttribute('src','https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js')
--> undefined
//驗(yàn)證一下
script
--> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script >
//通過.body.appendChild(script)將整個標(biāo)簽屬性值放置到頁面
document.body.appendChild(script)
--> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script >
//使用jquery
$
--> ? (e,t){return new w.fn.init(e,t)}
jQuery
--> ? (e,t){return new w.fn.init(e,t)}
5、innerHTML VS innerText
(1)innerHTML
假設(shè)獲取了一個dom元素,想知道頁面中的html元素是什么,或者放入很多東西(不通過創(chuàng)建dom節(jié)點(diǎn)的方式appendChild進(jìn)去)
頁面的一些菜單欄設(shè)置,通過后臺要數(shù)據(jù),后臺交還一個數(shù)組或json數(shù)據(jù)(包括菜單的所有信息),如何將菜單渲染到頁面上?通過字符串操作遍歷對象(或數(shù)組)去拼裝html字符串,拼接后一次性將html放置在空的節(jié)點(diǎn)下,則頁面看到了東西
幾個操作:Ajax獲取數(shù)據(jù)——數(shù)據(jù)到來之后拼接html字符串(遍歷、相加)——通過innerHtml方法將包含菜單信息的html字符串放在頁面上
//數(shù)組的值渲染做成一個菜單
var navbarDate =[1,2,3]
//寫一個空字符串,去拼接字符串的html
var html =' '
//遍歷這個數(shù)組
navbarDate.forEach(function(item){
html +='<li>'+item+'</li>' //將數(shù)組三個數(shù)拼在一起
})
--> undefined
html
--> "<li>1</li><li>2</li><li>3</li>" //無需換行,只需要拼接處html字符串即可
//可將生成的html字符串放在.navbar
document.querySelector('.navbar').innnerHTML = html
--> "<li>1</li><li>2</li><li>3</li>"
document.querySelector('.navbar')
--> <div class="navbar">...</div>
圖:
(2)innerText
看看所設(shè)置的元素標(biāo)簽下文本是什么(或設(shè)置它的文本)
注:沒有必要再創(chuàng)建什么元素標(biāo)簽,只需要設(shè)置一個空標(biāo)簽,然后設(shè)置它的innerText
續(xù)上面的例子:
document.querySelector('.navbar').innerText //作html去執(zhí)行
-->"1
2
3
"
假如代碼是這樣:
document.querySelector('.navbar').innerText = html //呈現(xiàn)給用戶
則將展示文本設(shè)置在頁面上,如圖:
五、常見的使用方式
1、修改樣式
可修改元素的style屬性,修改結(jié)果直接反映到頁面元素(不過,由于CSS權(quán)重的關(guān)系,雖然控制臺修改dom節(jié)點(diǎn)上的style屬性與頁面上的一一對應(yīng),但如果權(quán)重比不夠,修改的結(jié)果也不一定生效)
如:
//dom元素的style屬性上的 XXX與頁面上一一對應(yīng)
document.querySelector('p').style.color = 'red' //選中對應(yīng)元素,和修改對象+屬性
document.querySelector('.box').style.backgroundColor = '#ccc'
2、獲取樣式 getComputedStyle
不是獲取元素的style屬性,而是元素計(jì)算后的樣式(包括其他地方做的設(shè)置、瀏覽器默認(rèn)樣式、繼承樣式等綜合后的結(jié)果)。即
var node = document.querySelector('p')
var color = window.getComputedStyle(node).color //可直接使用,它是處在win的一個全局變量屬性
console.log(color)
如在控制臺想要獲取頁面dom元素的字體大小,如:
getComputedStyle(document.querySelector('#hello')) //獲取的是相對應(yīng)的對象,通過對象獲取對應(yīng)的style對應(yīng)的屬性
getComputedStyle(document.querySelector('#hello'))['font-size']//即獲取字體大小
//等同于
getComputedStyle(document.querySelector('#hello')).fontSize
3、class操作
當(dāng)使用樣式操作時,涉及到一些樣式的切換,可以直接去修改它的style,但這樣比較細(xì),且復(fù)雜。假設(shè)當(dāng)我們在頁面點(diǎn)擊一個按鈕時,整體發(fā)生一個很大的變化(包括字體大小、出現(xiàn)的邊框、背景色、背景圖片,甚至動畫效果),如果都是用style來操作,或?qū)е麓a冗長難修改,
我們可以將這些樣式放在一個css的class里面,如active。正常情況下是沒有這些class,當(dāng)我們點(diǎn)擊某個元素的時候,即鼠標(biāo)放上去時,給這個元素添加一個class
var nodeBox = document.querySelector('.box')
console.log( nodeBox.classList ) //通過選擇元素nodeBox去看看classList里擁有哪些class,
//即得到一個類數(shù)組對象.通過下標(biāo)的方式獲取class
nodeBox.classList.add('active') //新增 class
nodeBox.classList.remove('active') //刪除 class
nodeBox.classList.toggle('active') //新增/刪除切換
node.classList.contains('active') // 判斷是否擁有 class
如圖:http://js.jirengu.com/ponaz/1/edit?html,css,js,output
class操作,不用擔(dān)心class的數(shù)量有多少,無需擔(dān)心同名、正則,只需要采用這種原生JS的API就能操作頁面dom元素
4、頁面寬高的計(jì)算
(1)element.clientHeight VS element.clientWidth
獲取元素窗口的高度、寬度
(2)element.offsetHeight VS element.offsetWidth
獲?。ò吙?內(nèi)邊距+窗口整體)的高度、寬度
獲取兩種的寬高,得到的結(jié)果看具體情況,有些時候是相同,有些時候是不同,如圖:
(3)element.scrollHeight
元素滾動內(nèi)容的總長度,也分實(shí)際情況
假設(shè)頁面上有一處包含內(nèi)容的div塊級,頁面若為可滾動的,表示內(nèi)容長度超出它容器的高度,而容器高度已為固定寬高,此時scrollHeight>clientHeight
若頁面若無滾動條、父容器高度沒有固定,則scrollHeight=clientHeight=offsetHeight
(4)element.scrollTop
獲取元素滾動的高度,即滾動時滾動了一定的值
document.body.scrollTop
(5)window.innerHeight
窗口的高度
window.innerHeigh
實(shí)例操作:http://js.jirengu.com/fuser/1/edit?html,css
以下問題跟之后的解決懶加載有密切聯(lián)系
問題1:如何去判斷一個元素是否出現(xiàn)在窗口的視野中
問題2:如何判斷頁面滾動到底部
元素到頂點(diǎn)的值=滾動的值
元素滾動的距離+窗口的高度=這個元素到頂點(diǎn)的距離