DOM
文檔對象模型 (DOM) 是HTML和XML文檔的編程接口雇寇。它給文檔(結(jié)構(gòu)樹)提供了一個結(jié)構(gòu)化的表述并且定義了一種方式—程序可以對結(jié)構(gòu)樹進(jìn)行訪問魄缚,以改變文檔的結(jié)構(gòu)君丁,樣式和內(nèi)容。
DOM 提供了一種表述形式將文檔作為一個結(jié)構(gòu)化的節(jié)點(diǎn)組以及包含屬性和方法的對象昭殉。從本質(zhì)上說棵癣,它將web 頁面和腳本或編程語言連接起來了辕翰。
要改變頁面的某個東西,JavaScript就需要獲得對HTML文檔中所有元素進(jìn)行訪問的入口狈谊。這個入口喜命,連同對 HTML 元素進(jìn)行添加、移動河劝、改變或移除的方法和屬性壁榕,都是通過DOM來獲得的
document 對象
每個載入瀏覽器的HTML文檔都會成為document
對象。document對象包含了文檔的基本信息赎瞎,我們可以通過JavaScript對HTML頁面中的所有元素進(jìn)行訪問牌里、修改。
document對象常用屬性
document對象有很多屬性來描述文檔信息务甥,介紹幾個常用的
document.doctype
document.title
document.characterSet
document.head
document.body //例如牡辽,我們想往body中加一些新的屬性喳篇,就可以這樣調(diào)用
document.images
/*了解
readyState屬性返回當(dāng)前文檔的狀態(tài),共有三種可能的值
1\. loading:加載HTML代碼階段态辛,尚未完成解析
2\. interactive:加載外部資源階段
3\. complete:全部加載完成
*/
document.readyState
/*了解
compatMode 屬性返回瀏覽器處理文檔的模式麸澜,可能的值為
1\. BackCompat:向后兼容模式,也就是沒有添加DOCTYPE
2\. CSS1Compat:嚴(yán)格模式因妙,添加了DOCTYPE
*/
document.compatMode
document.location
document.location 也可直接使用 location
document.location === location //true
document.location === window.location //true
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"
// 跳轉(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()
雖然location屬性返回的對象是只讀的以故,但是可以將URL賦值給這個屬性,網(wǎng)頁就會自動跳轉(zhuǎn)到指定網(wǎng)址裆操。
document.location = 'http://www.example.com';
// 等價(jià)于
document.location.;
document.open()怒详、document.close()
document.open方法用于新建一個文檔,供write方法寫入內(nèi)容踪区。它實(shí)際上等于清除當(dāng)前文檔昆烁,重新寫入內(nèi)容
document.close方法用于關(guān)閉open方法所新建的文檔。一旦關(guān)閉缎岗,write方法就無法寫入內(nèi)容了静尼。
document.write()
document.write方法用于向當(dāng)前文檔寫入內(nèi)容。只要當(dāng)前文檔還沒有用close方法關(guān)閉传泊,它所寫入的內(nèi)容就會追加在已有內(nèi)容的后面鼠渺。
document.open();
document.write("hello");
document.write("world");
document.close();
如果頁面已經(jīng)渲染完成再調(diào)用write方法,它會先調(diào)用open方法眷细,擦除當(dāng)前文檔所有內(nèi)容拦盹,然后再寫入。
如果在頁面渲染過程中調(diào)用write方法溪椎,并不會調(diào)用open方法普舆。
需要注意的是,雖然調(diào)用close方法之后校读,無法再用write方法寫入內(nèi)容奔害,但這時(shí)當(dāng)前頁面的其他DOM節(jié)點(diǎn)還是會繼續(xù)加載。
除了某些特殊情況地熄,應(yīng)該盡量避免使用document.write這個方法华临。
Element
除了document對象,在DOM中最常用的就是Element對象了端考,Element對象表示HTML元素雅潭。
Element 對象可以擁有類型為元素節(jié)點(diǎn)揭厚、文本節(jié)點(diǎn)、注釋節(jié)點(diǎn)的子節(jié)點(diǎn)扶供,DOM提供了一系列的方法可以進(jìn)行元素的增筛圆、刪、改椿浓、查操作
Element有幾個重要屬性
- nodeName:元素標(biāo)簽名太援,還有個類似的tagName
- nodeType:元素類型
- className:類名
- id:元素id
- children:子元素列表(HTMLCollection)
- childNodes:子元素列表(NodeList)
- firstChild:第一個子元素
- lastChild:最后一個子元素
- nextSibling:下一個兄弟元素
- previousSibling:上一個兄弟元素
- parentNode、parentElement:父元素
查詢元素
getElementById()
getElementById方法返回匹配指定ID屬性的元素節(jié)點(diǎn)扳碍。如果沒有發(fā)現(xiàn)匹配的節(jié)點(diǎn)提岔,則返回null。這也是獲取一個元素最快的方法
var elem = document.getElementById("test");
說明:我們要對一個元素進(jìn)行css樣式的添加笋敞,或者添加一個屬性碱蒙,首先應(yīng)該選中它
進(jìn)一步選中元素
getElementsByClassName()
getElementsByClassName方法返回一個類似數(shù)組的對象(HTMLCollection類型的對象),包括了所有class名字符合指定條件的元素(搜索范圍包括本身)夯巷,元素的變化實(shí)時(shí)反映在返回結(jié)果中赛惩。這個方法不僅可以在document對象上調(diào)用,也可以在任何元素節(jié)點(diǎn)上調(diào)用趁餐。
var elements = document.getElementsByClassName('tab');
getElementsByClassName方法的參數(shù)喷兼,可以是多個空格分隔的class名字,返回同時(shí)具有這些節(jié)點(diǎn)的元素后雷。
document.getElementsByClassName('red test');
getElementsByTagName()
getElementsByTagName方法返回所有指定標(biāo)簽的元素(搜索范圍包括本身)褒搔。返回值是一個HTMLCollection對象,也就是說喷面,搜索結(jié)果是一個動態(tài)集合星瘾,任何元素的變化都會實(shí)時(shí)反映在返回的集合中。這個方法不僅可以在document對象上調(diào)用惧辈,也可以在任何元素節(jié)點(diǎn)上調(diào)用琳状。
var paras = document.getElementsByTagName("p");
上面代碼返回當(dāng)前文檔的所有p元素節(jié)點(diǎn)。注意盒齿,getElementsByTagName方法會將參數(shù)轉(zhuǎn)為小寫后念逞,再進(jìn)行搜索。
getElementsByName()
getElementsByName方法用于選擇擁有name屬性的HTML元素边翁,比如form翎承、img、frame符匾、embed和object叨咖,返回一個NodeList格式的對象,不會實(shí)時(shí)反映元素的變化。
// 假定有一個表單是<form name="x"></form>
var forms = document.getElementsByName("x");
forms[0].tagName // "FORM"
注意甸各,在IE瀏覽器使用這個方法垛贤,會將沒有name屬性、但有同名id屬性的元素也返回趣倾,所以name和id屬性最好設(shè)為不一樣的值聘惦。
querySelector()
querySelector方法返回匹配指定的CSS選擇器的元素節(jié)點(diǎn)。如果有多個節(jié)點(diǎn)滿足匹配條件儒恋,則返回第一個匹配的節(jié)點(diǎn)善绎。如果沒有發(fā)現(xiàn)匹配的節(jié)點(diǎn),則返回null诫尽。
var el1 = document.querySelector(".myclass");
var el2 = document.querySelector('#myParent > [ng-click]');
querySelector方法無法選中CSS偽元素禀酱。
querySelectorAll()
querySelectorAll方法返回匹配指定的CSS選擇器的所有節(jié)點(diǎn),返回的是NodeList類型的對象箱锐。NodeList對象不是動態(tài)集合比勉,所以元素節(jié)點(diǎn)的變化無法實(shí)時(shí)反映在返回結(jié)果中劳较。
elementList = document.querySelectorAll(selectors);
querySelectorAll方法的參數(shù)驹止,可以是逗號分隔的多個CSS選擇器,返回所有匹配其中一個選擇器的元素观蜗。
var matches = document.querySelectorAll("div.note, div.alert");
上面代碼返回class屬性是note或alert的div元素臊恋。
querySelector與querySelectorAll的區(qū)別
兼容性
創(chuàng)建元素
createElement()
使用場景舉例
1.例如,我點(diǎn)擊了一個按鈕墓捻,然后選擇了h1這個節(jié)點(diǎn)抖仅,在其中添加圖片
2.又比如,我在head中添加一個script砖第,然后添加一個src撤卢,添加一個jquery
createElement方法用來生成HTML元素節(jié)點(diǎn)。
var newDiv = document.createElement("div");
createElement方法的參數(shù)為元素的標(biāo)簽名梧兼,即元素節(jié)點(diǎn)的tagName屬性放吩。如果傳入大寫的標(biāo)簽名,會被轉(zhuǎn)為小寫羽杰。如果參數(shù)帶有尖括號(即<和>)或者是null渡紫,會報(bào)錯。
createTextNode()
createTextNode方法用來生成文本節(jié)點(diǎn)考赛,參數(shù)為所要生成的文本節(jié)點(diǎn)的內(nèi)容惕澎。
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
上面代碼新建一個div節(jié)點(diǎn)和一個文本節(jié)點(diǎn)
createDocumentFragment()
createDocumentFragment方法生成一個DocumentFragment對象。
var docFragment = document.createDocumentFragment();
DocumentFragment對象是一個存在于內(nèi)存的DOM片段颜骤,但是不屬于當(dāng)前文檔唧喉,常常用來生成較復(fù)雜的DOM結(jié)構(gòu),然后插入當(dāng)前文檔。這樣做的好處在于欣喧,因?yàn)镈ocumentFragment不屬于當(dāng)前文檔腌零,對它的任何改動,都不會引發(fā)網(wǎng)頁的重新渲染唆阿,比直接修改當(dāng)前文檔的DOM有更好的性能表現(xiàn)益涧。
說明:當(dāng)我們使用createElement來創(chuàng)建元素的時(shí)候,例如驯鳖,現(xiàn)在有一個數(shù)組闲询,里面有100個元素,通過遍歷將這些元素變成對象浅辙,然后將這100個對象插入到某個div中扭弧,那么這時(shí)會對頁面進(jìn)行100次重繪,但如果我們使用
createDocumentFragment()记舆,可以先將這些對象存入其中鸽捻,然后再將createDocumentFragment()導(dǎo)入html中,這樣就重繪了一次泽腮,性能好很多御蒲。
修改元素
appendChild()
在元素末尾添加元素
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.appendChild(newContent);
insertBefore()
在某個元素之前插入元素
var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.insertBefore(newContent, newDiv.firstChild);
replaceChild()
replaceChild()接受兩個參數(shù):要插入的元素和要替換的元素
newDiv.replaceChild(newElement, oldElement);
刪除元素
刪除元素使用removeChild()方法即可
parentNode.removeChild(childNode);
clone元素
cloneNode()方法用于克隆元素,方法有一個布爾值參數(shù)诊赊,傳入true的時(shí)候會深復(fù)制厚满,也就是會復(fù)制元素及其子元素(IE還會復(fù)制其事件),false的時(shí)候只復(fù)制元素本身
node.cloneNode(true);
屬性操作
getAttribute()
getAttribute()用于獲取元素的attribute值(實(shí)際就是獲取元素的屬性值)
node.getAttribute('id'); //這里就是去獲取元素的id屬性值碧磅,獲取img的src屬性也是如此
說明:圖中獲取img的src屬性
createAttribute()
createAttribute()方法生成一個新的屬性對象節(jié)點(diǎn)碘箍,并返回它。
attribute = document.createAttribute(name);
createAttribute方法的參數(shù)name鲸郊,是屬性的名稱丰榴。
setAttribute()
setAttribute()方法用于設(shè)置元素屬性
var node = document.getElementById("div1");
node.setAttribute("my_attrib", "newVal");
等同于
var node = document.getElementById("div1");
var a = document.createAttribute("my_attrib");
a.value = "newVal";
node.setAttributeNode(a);
實(shí)例
romoveAttribute()
removeAttribute()用于刪除元素屬性
node.removeAttribute('id');
說明:對比getAttribute的img秆撮,src屬性被移除
element.attributes
當(dāng)然上面的方法做的事情也可以通過類操作數(shù)組屬性element.attributes來實(shí)現(xiàn)
innerText
innerText是一個可寫屬性四濒,返回元素內(nèi)包含的文本內(nèi)容,在多層次的時(shí)候會按照元素由淺到深的順序拼接其內(nèi)容
比如說我們選擇了一個元素像吻,可以通過innerText獲取其中的文本元素峻黍,例如,在下面的例子中拨匆,我們選擇了這個div姆涩,將會過濾所有的標(biāo)簽,就保留其中的123456
<div>
<p>
123
<span>456</span>
</p>
</div>
外層div的innerText返回內(nèi)容是 "123456"
innerHTML
innerHTML屬性作用和innerText類似惭每,但是不是返回元素的文本內(nèi)容骨饿,而是返回元素的HTML結(jié)構(gòu)亏栈,在寫入的時(shí)候也會自動構(gòu)建DOM
相當(dāng)于當(dāng)我們選中一個元素時(shí),返回他的所有的html標(biāo)簽
<div>
<p>
123
<span>456</span>
</p>
</div>
外層div的innerHTML返回內(nèi)容是 "<p>123<span>456</span></p>"
innerHTML使用實(shí)例
innerText和innerHTML的對比
innerText和innerHTML是可讀可寫的宏赘,所以也可以將它賦值绒北?
常見使用方式
修改樣式
可修改元素的 style 屬性,修改結(jié)果直接反映到頁面元素
document.querySelector('p').style.color = 'red'
document.querySelector('.box').style.backgroundColor = '#ccc'
獲取樣式 getComputedStyle
使用getComputedStyle獲取元素計(jì)算后的樣式察署,不要通過 node.style.屬性
獲取
var node = document.querySelector('p')
var color = window.getComputedStyle(node).color
console.log(color)
class 操作
var nodeBox = document.querySelector('.box')
console.log( nodeBox.classList )
nodeBox.classList.add('active') //新增 class
nodeBox.classList.remove('active') //刪除 class
nodeBox.classList.toggle('active') //新增/刪除切換
node.classList.contains('active') // 判斷是否擁有 class
樣式的改變盡量使用 class 的新增刪除來實(shí)現(xiàn)
<iframe src="http://js.jirengu.com/nupom/1/embed" class="" id="" style="box-sizing: border-box; -webkit-tap-highlight-color: transparent; text-size-adjust: none; -webkit-font-smoothing: antialiased; font-size: inherit; border: 1px solid rgb(170, 170, 170); width: 770px; min-height: 300px; height: 213px;"></iframe>
頁面寬高
element.clientHeight
element.offsetHeight
document.body.clientHeight
document.body.offsetHeight
docuemnt.body.style.border = "10px solid red"
docuemnt.body.clientHeight //變小了
document.body.offsetHeight
element.scrollHeight 元素滾動內(nèi)容的總長度闷游。如果元素沒出現(xiàn)滾動條, scrollHeight等于 clientHeight
document.body.scrollHeight
element.scrollTop 滾動的高度
document.body.scrollTop
window.innerHeight 窗口的高度
window.innerHeigh
element.getBoundingClientRect() 獲取元素在視窗中的位置
問題1: 如果判斷一個元素距離 document 頂部的偏移
function getOffsetTop( elem ){
var offsetLeft = 0
do {
offsetTop += elem.offsetTop
} while( elem = elem.offsetParent )
return offsetTop
}
或者
element.getBoundingClientRect().top + document.body.scrollTop
問題2:如何判斷一個元素是否出現(xiàn)在窗口視野中
問題3:如果判斷頁面滾動到底部
HTMLCollection 和 NodeList
節(jié)點(diǎn)都是單個對象贴汪,有時(shí)會需要一種數(shù)據(jù)結(jié)構(gòu)脐往,能夠容納多個節(jié)點(diǎn)。DOM提供兩種集合對象扳埂,用于實(shí)現(xiàn)這種節(jié)點(diǎn)的集合:NodeList和HTMLCollection业簿。
NodeList 對象代表一個有順序的節(jié)點(diǎn)列表,HTMLCollection 是一個接口阳懂,表示 HTML 元素的集合呜达,它提供了可以遍歷列表的方法和屬性
以下方法獲取的為HTMLCollection對象
document.images //所有img元素
document.links //所有帶href屬性的a元素和area元素
document.forms //所有form元素
document.scripts //所有script元素
document.body.children
document.getElementsByClassName("class1")
以下方法獲取的為NodeList對象
document.getElementsByName("name1")
document.getElementsByTagName("a")
document.querySelectorAll("a")
document.body.childNodes
如何查看花颗?
document.body.childNodes.constructor
HTMLCollection與NodeList基本相似
相同點(diǎn): 都是類數(shù)組對象糯崎,節(jié)點(diǎn)的變化都會實(shí)時(shí)反映在集合中
不同點(diǎn): 少部分方法不一樣轻黑,比如 NodeList 有 forEach 方法婿禽,而 HTMLCollection 沒有
參考
Difference between HTMLCollection, NodeLists, and arrays of objects