以下內(nèi)容總結(jié)自《js高級程序設(shè)計 第三版》
今天來說說JS中的DOM以及DOM操作。
DOM是什么,做了什么屯仗?
DOM是針對HTML和XML文檔的一個API,也叫文檔對象模型搔谴。
DOM描繪了一個層次化的節(jié)點樹魁袜,允許開發(fā)人員添加,移除,修改頁面的某一部分峰弹。
DOM并不難店量,但需要各位同學(xué)記憶和了解的部分居多,所以本章少說廢話鞠呈,API部分盡量簡單明了融师,供各位同學(xué)參閱。
一蚁吝、節(jié)點層次
剛才說過旱爆,DOM是一個節(jié)點樹,既然是樹窘茁,那肯定就會分層級怀伦。
以HTML為例,它的結(jié)構(gòu)如下
<html>
<head>
<title>ATitle</title>
</head>
<body>
<p>Hello World :)</p>
</body>
</html>
是不是感覺根節(jié)點是最外層的<html>標簽山林?誒房待,并不是。
文檔節(jié)點才是每個文檔(這里指這個HTML頁面)的根節(jié)點驼抹。而文檔節(jié)點的子節(jié)點吴攒,才是<html>元素。
我們也叫<html>元素為文檔元素砂蔽,它是元素中的老大洼怔,所有的其他元素都包含在<html>中。
每一個文檔只能有一個文檔元素左驾。在HTML中镣隶,始終就是<html>;而在XML中诡右,據(jù)隨便了安岂,誰都可能成為文檔元素。
了解了大概的層級帆吻,接下來就得看看每層都是什么類型的節(jié)點域那。畢竟,類型不同猜煮,干的活也不一樣次员。
1 Node類型
一個文檔中,總會有多種類型的節(jié)點配合使用王带,這樣做才會分工明確淑蔚,邏輯清晰。
在JS中愕撰,所有的節(jié)點類型都繼承自Node類型刹衫,所以它們共享著一些相同的基本屬性和方法醋寝。
我們先來說說都有哪些節(jié)點類型,再來講講共同屬性带迟,方法音羞。
Node.ELEMENT_NODE(1)
Node.ATTRIBUTE_NODE(2)
Node.TEXT_NODE(3)
Node.CDATA_SECTION_NODE(4)
Node.ENTITY_REFERENCE_NODE(5)
Node.ENTITY_NODE(6)
Node.PROCESSING_INSTRUCTION_NODE(7)
Node.COMMENT_NODE(8)
Node.DOCUMENT_NODE(9)
Node.DOCUMENT_TYPE_NODE(10)
Node.DOCUMENT_FRAGMENT_NODE(11)
Node.NOTATION_NODE(12)
每個節(jié)點的類型必是其中之一,雖然這里12個類型看著密密麻麻的有點慌仓犬,但是不用怕嗅绰,我們Web瀏覽器也不是全部都支持的,而且比較常用的就是元素和文本節(jié)點婶肩。
接下來就說一下節(jié)點的屬性和方法。
共同屬性:
nodeType貌夕、nodeName律歼、nodeValue、
childNode啡专、parentNode险毁、
perviousSibling、nextSibling们童、
firstChild畔况、lastChild、
ownerDocument
nodeType
nodeType 是用來查看節(jié)點類型的慧库,我們可以這樣做
if(nodeType === Node.ELEMENT_NODE){
console.log('Node is a element')
}
但是由于IE沒有公開Node類型的構(gòu)造函數(shù)跷跪,所以我們想跨瀏覽器兼容的話,就得這樣做
// 所有瀏覽器適用
if(nodeType === 1){
console.log('Node is a element')
}
雖然寫法更簡單了齐板,但是IE坑還是非常多的比然,珍愛秀發(fā)云茸,遠離IE。
nodeName和nodeValue
這兩個屬性的值取決于及節(jié)點的類型。
常用的元素節(jié)點(ndeoType == 1)库倘,它的nodeName就是標簽名,而nodeValue是null抵怎。
其他類型的話各谚,見到再說吧。
childNodes
在這個屬性存放著一個NodeList類對象數(shù)組滋觉。
這里需要知道的兩點:
1 NodeList是一個像數(shù)組卻不是數(shù)組的對象签夭,按順序存放著一個節(jié)點的所有子元素;
2 NodeList是‘活’的椎侠,DOM結(jié)構(gòu)變化它就跟著變覆致。
我們可以像使用數(shù)組那樣使用它
// 使用[]
const firstChild = some.childNodes[0]
// 使用item(n)
const secondChild = some.childNodes.item(1)
// 獲取長度
const count = some.childNodes.length
parentNode
父節(jié)點,誰包著當前節(jié)點肺蔚,parentNode就指向誰煌妈。
perviousSibling、nextSibling
perviousSibling:同級的前面一個節(jié)點
nextSibling: 同級的后面一個節(jié)點
當前節(jié)點是第一個或者最后一個時,perviousSibling或nextSibling為null
firstChild璧诵、lastChild
firstChild: 一個節(jié)點的第一個子節(jié)點
lastChild:一個節(jié)點的最后一個子節(jié)點
沒有子節(jié)點firstChild和lastChild都為null
ownerDocument
該屬性指向整個文檔的文檔節(jié)點汰蜘。
共同方法:
適用于有子節(jié)點的節(jié)點:appendChild()、insertBefore()之宿、replaceChild()族操、removeChild()
適用于所有節(jié)點:cloneChild()、normalize()
appendChild()
向父節(jié)點內(nèi)最后的位置添加一個節(jié)點比被,返回值為插入后的該節(jié)點
const returnedNode = someNode.appendChild(someNode.firstChild)
alert(returnedNode === someNode.firstNode) // false
alert(returnedNode === someNode.lastNode) // true
insertBefore()
向父節(jié)點內(nèi)的某個節(jié)點前插入一個節(jié)點色难。
第一個參數(shù):要插入的節(jié)點,
第二個參數(shù):被插入的節(jié)點(為null時等缀,新節(jié)點插到最后)
返回值: 插入后的該節(jié)點
// 向第一個節(jié)點前插入一個節(jié)點
someNode.insertBefore(newNode,someNode.firstChild)
replaceChild()
替換一個節(jié)點
第一個參數(shù):要插入的節(jié)點
第二個參數(shù):被替換的節(jié)點
返回值: 替換后的該節(jié)點
// 替換第一個節(jié)點
someNode.replaceChild(newNode,someNode.firstChild)
removeChild()
移除一個節(jié)點
第一個參數(shù):要移除的節(jié)點
第二個參數(shù):被替換的節(jié)點
返回值: 移除后的該節(jié)點
// 移除第一個節(jié)點
someNode.removeChild(newNode,someNode.firstChild)
cloneChild()
復(fù)制一個節(jié)點
參數(shù):true \ false
(true時是深復(fù)制枷莉,也就是包含該節(jié)點和內(nèi)部的所有子節(jié)點;false時尺迂,只復(fù)制當前節(jié)點)
返回值: 節(jié)點列表
normalize()
操作文本節(jié)點
在某個節(jié)點調(diào)用該方法時笤妙,會去其后代節(jié)點中做兩件事:
1 刪除空文本節(jié)點
2 合并相鄰文本節(jié)點
2、Document類型
前面說過噪裕,所有的節(jié)點類型都是是繼承自Node類型蹲盘,所以,Document類型節(jié)點以及本節(jié)后面所有的節(jié)點膳音,都是兒子召衔。
Document表示文檔。在瀏覽器中祭陷,document對象是HTMLDocument(它又繼承自Document類型薄嫡,所以是孫子輩的)的一個實例,表示整個HTML頁面颗胡。
而且毫深,document對象又是window對象的一個屬性,所以可以將其作為全局對象來訪問毒姨。
特征:
1 nodeType 值為9
2 nodeName 值為 "#document"
3 nodeVlaue 值為null
4 parentNode 值為null
5 ownerDocument 值為null
6 其子節(jié)點可能是一個DocumentType(最多一個)哑蔫、Element(最多一個)、ProcessingInstruction或Comment
Document類型的屬性
documentElement弧呐、body闸迷、doctype、title俘枫、
URL腥沽、domain、referrer鸠蚪、
anchors今阳、applets师溅、forms、images盾舌、links墓臭、
implementation
>1、documentElement妖谴、body窿锉、doctype、title
documentElement: 對<html>的引用
body: 對<body>的引用
doctype: 對<!DOCTYPE>的引用膝舅、
title: 對<title>的引用
>2嗡载、URL、domain仍稀、referrer
URL: 當前頁面的網(wǎng)址
domain: 當前頁面的域名
referrer: 來源頁面的URL(當前頁面是在哪打開的)
其中domain可以設(shè)置洼滚,但亂改是不行的,只能是當前URL的子域名琳轿。
>3判沟、anchors耿芹、applets崭篡、forms、images吧秕、links
anchors:所有帶name特性的<a>元素
applets:所有<applets>元素(不推薦使用琉闪,了解即可)
forms:所有<form>元素
images:所有<img>元素
links:所有帶href特性的<a>元素
>4、implementation
這個屬性是用來提供相關(guān)信息和功能的對象砸彬,來查看瀏覽器實現(xiàn)了對應(yīng)的哪些功能颠毙。
它有一個特定的方法hasFeature(),接收兩個參數(shù)
第一個參數(shù):要檢測的DOM功能的名稱
第二個參數(shù):要檢測的DOM功能的版本號
使用方法如下
// 返回true或false
cosnt result = document.implementation.hasFeature('XML','1.0')
下面是可以檢測的值砂碉,看看就好蛀蜜。
Document類型的方法
getElementById()增蹭、 getElementsByTagName()滴某、getElementsByName()、
write()滋迈、writeln()霎奢、open()、close()
>1饼灿、getElementById()
根據(jù)節(jié)點id值獲取節(jié)點幕侠,只能獲取一個節(jié)點
這應(yīng)該是大家最常用的方法了
>2、getElementsByTagName()
根據(jù)標簽名獲取節(jié)點列表(是一個HTMLCollection 類數(shù)組對象)
const images = document.getElementByTagName('img')
alert(images.length)
alert(images[0].src)
alert(images.item(0).src)
// 特有方法碍彭,根據(jù)name屬性獲取節(jié)點
images.namedItem('aName')
// 或者這樣寫
images['aName']
//-----------------------------------
// 獲取全部
document.getElementByTagName('*')
我想聰明的你都能看懂晤硕。
>3悼潭、getElementsByName()
根據(jù)節(jié)點的name屬性的值獲取節(jié)點列表。(HTMLDocument類型特有方法)
>4窗骑、write()女责、writeln()、open()创译、close()
write(): 寫入抵知,接受一個字符串參數(shù)
writeln(): 在write的基礎(chǔ)上在結(jié)尾加個 '\n'
open(): 打開網(wǎng)頁輸入流 // 不怎么用
close(): 關(guān)閉網(wǎng)頁輸入流 // 不怎么用
3、Element類型
又是一個常見的節(jié)點類型软族,Element類型常用于表示XML或HTML元素刷喜。
特征:
1 nodeType 值為1
2 nodeName 值為元素的標簽名
3 nodeVlaue 值為null
4 parentNode 值可能為Document或Element
5 ownerDocument 值為null
6 其子節(jié)點可能是Element、Text立砸、Comment掖疮、ProcessingInstruction、CDATASection或EntryReference
Element類型的屬性
nodeName颗祝、tagName浊闪、
id、title螺戳、lang搁宾、dir、className倔幼、
attributes
>1盖腿、nodeName、tagName
兩個屬性等價损同,返回值為元素的標簽名翩腐。
>2、id膏燃、title茂卦、lang、dir组哩、className
id:元素id屬性
title:元素title屬性(鼠標放上去顯示的就是title屬性)
lang:元素lang屬性(語言代碼等龙,很少使用)
dir:元素dir屬性 (文字排列方向,值為 'ltr'(left-to-right) 或 'rtl'(right-to-left))
className:元素class屬性
舉個例子
<div id="myDiv" class="bd" title="Body Text" lang="en" dir="ltr"></div>
當然除了獲取禁炒,也可以給這幾個屬性直接賦值而咆。
>3、attributes
這個屬性厲害了幕袱,Element類型專屬暴备。
返回一個NameNodeMap類數(shù)組對象。其中包含著這個元素的所有屬性和值的鍵值對们豌。
同時涯捻,attributes還擁有下列的方法
getNamedItem(name): 返回屬性為name的鍵值對
removeNamedItem(name): 移除屬性為name的鍵值對
setNamedItem(node): 添加鍵值對浅妆,以node.nodeName屬性為索引
item(pos): 返回位于數(shù)字pos位置處的節(jié)點
例
// 獲取
const id = element.attributes.getNamedItem('id').nodeValue
// 或者這樣訪問
const id = element.attributes['id'].nodeValue
// 移除
element.attributes.removeNamedItem('id')
// 添加(不常用)
element.attributes.setNamedItem(newAttr)
attributes的作用
遍歷元素的屬性,當然不同瀏覽器遍歷得到的屬性順序可能不同 (遠離IE障癌,尤其是低版本)
Element類型的方法
getAttributes()凌外、setAttributes()、removeAttributes()
>1涛浙、getAttributes()
獲取元素屬性的方法康辑,標簽中屬性名是啥,就傳入對應(yīng)的字符串當作參數(shù)轿亮。
不過有兩個特殊的屬性名:
1 style: 通過該方法訪問返回字符串疮薇;通過屬性名直接返回一個對象。
2 事件:像onclick這樣的事件我注。通過方法訪問得到代碼字符串或null按咒;通過屬性名訪問得到一個函數(shù)。
>2但骨、setAttributes()
和getAttributes()對應(yīng)励七,設(shè)置屬性值
接收兩個參數(shù)
1 屬性名
2 屬性值
例
div.setAttribute('id','someOtherId')
>3奔缠、removeAttributes()
移除屬性掠抬,不常用
根據(jù)個人經(jīng)驗(菜雞水平)來說,沒用過添坊。
一個來自document的方法
document.createment()
作用:創(chuàng)建一個新元素
接受參數(shù):一個剿另,為 標簽名
使用:配合Element中給新元素添加屬性箫锤,最后再用插入元素的方法(忘記的同學(xué)回到上面再看看)添加到想放的地方贬蛙。
4、Text類型
就是文本節(jié)點
特征:
1 nodeType 值為3
2 nodeName 值為"#text"
3 nodeVlaue 值為節(jié)點所包含的文字
4 parentNode 值是一個Element
5 ownerDocument 值為null
6 沒有子節(jié)點
Text類型的屬性
data谚攒、length
>1阳准、data
文本節(jié)點的內(nèi)容,和nodeValue的值相同馏臭。
>2野蝇、length
字符的數(shù)目。
Text類型的方法
appendData()括儒、deleteData()绕沈、insertData()、replaceData()帮寻、splitText()乍狐、subStringData()
>1、appendData(text)
將text添加到節(jié)點末尾
>2固逗、deleteData(offset浅蚪,count)
刪除從offset位置開始的的count個字符藕帜。
>3、insertData(offset惜傲,text)
從offset位置開始插入text洽故。
>4、replaceData(offset盗誊,count时甚,text)
用text替換從從offset位置開始的的count個字符。
>5哈踱、splitText(offset)
從offset位置分割成兩個文本節(jié)點
>6撞秋、subStringData(offset,count)
提取從offset開始的count個字符組成的文本
來自document的方法
document.createTextNode()
作用:創(chuàng)建新的文本節(jié)點
參數(shù):傳一個字符串
使用:配合插入節(jié)點的方法使用嚣鄙。
規(guī)范化文本節(jié)點
前面提到過document.normalize()
它的兩個作用再提一遍:
1 刪除空文本節(jié)點
2 合并相鄰文本節(jié)點
5吻贿、Comment類型
注釋節(jié)點類型。
特征:
1 nodeType 值為8
2 nodeName 值為"#comment"
3 nodeVlaue 值為注釋的內(nèi)容
4 parentNode 值可能是Document或Element
5 沒有子節(jié)點
Commit類型和Text類型繼承自相同的基類哑子,它的方法除了splitText()之外和Text類型沒有區(qū)別舅列。所以參考上面即可。
6卧蜓、CDATASection類型
針對XML的文檔類型帐要,表示CDATA區(qū)域,了解即可弥奸。
特征:
1 nodeType 值為4
2 nodeName 值為"#cdata-section"
3 nodeVlaue 值為CDATA區(qū)域中的內(nèi)容
4 parentNode 值可能是Document或Element
5 沒有子節(jié)點
7榨惠、DocumentType類型
不常用,甚至只有部分瀏覽器支持盛霎,了解即可赠橙。
特征:
1 nodeType 值為10
2 nodeName 值為doctype的名稱
3 nodeVlaue 值為null
4 parentNode 值是Document
5 沒有子節(jié)點
8、DocumentFragment類型
文檔片段節(jié)點類型愤炸。
特征:
1 nodeType 值為11
2 nodeName 值為"#document-fragment"
3 nodeVlaue 值為null
4 parentNode 值是null
5 子節(jié)點可以是Element期揪、ProcessingInstruction、Comment规个、Text凤薛、CDATASection、EntryReference
文檔片段節(jié)點比較特殊诞仓,它就像整個文檔掰碎了的碎片缤苫,能向文檔節(jié)點一樣操作其內(nèi)的節(jié)點。
可以使用插入節(jié)點的方法將文檔片段插入到文檔中墅拭。
應(yīng)用:
代替多次插入節(jié)點活玲,先將所有的節(jié)點插入到文檔片段中,再將文檔片段插入到文檔中。
9翼虫、Attr類型
元素特性類型屑柔。指HTML標簽中屬性。
特征:
1 nodeType 值為2
2 nodeName 值為特性的名稱
3 nodeVlaue 值為特性的值
4 parentNode 值是null
5 子節(jié)點:在HTML中沒有珍剑;在XML中可以是Text或在EntryReference
雖然被定義成節(jié)點掸宛,但Attr類型被嫌棄了,它不被認可是DOM文檔樹的一部分招拙。
Attr類型的屬性
name唧瘾、value、specified
>1别凤、name饰序、value、specified
name: 屬性名
value: 屬性值
specified:布爾值规哪,用來區(qū)分是特性是在代碼中指定的還是默認的
來自document的方法
document.createAttribute()
作用:創(chuàng)建一個Attr類型節(jié)點
參數(shù):屬性名(字符串)
使用:使用.value方式賦值求豫,配合setAttributeNode將Attr類型節(jié)點放到元素中。
建議
使用Element節(jié)點的getAttribute()诉稍、setAttribute()蝠嘉、removeAttribute()代替使用Attr節(jié)點的屬性。
因為更方便杯巨,不用再創(chuàng)建Attr類型了蚤告。
二、DOM操作技術(shù)
"DOM操作是簡單的服爷,但IE是坑的杜恰。"
所以這里我們拋開IE,擁抱主流仍源。
1心褐、動態(tài)腳本
有多種方法能夠向頁面插入js代碼
1 <script></script>內(nèi)部包含js代碼
2 <script> 的src屬性引入外部js
3 使用DOM操作生成<script>標簽和js代碼
動態(tài)腳本講的就是第三種方法。
我們可以這樣操作:
var script = document.createElement('script')
script.type = 'text/javascript'
// client.js是一個外部js文件镜会,這里假裝有一個
script.src= 'client.js'
document.body.appendChild(script)
這就動態(tài)添加了一個腳本檬寂。
甚至可以將以上代碼封裝到一個函數(shù)中终抽,在合適的時機進行調(diào)用戳表。
2、動態(tài)樣式
將css包含到頁面的方法也有多種
1 使用<link>標簽引入外部css文件
2 使用<style>包含css代碼
3 使用DOM操作動態(tài)生成css代碼
舉例:
var link = document.createElement('link')
link.rel = 'stylesheet'
link.type = 'text/css'
link.href = 'styles.css'
var head = document.getElementsByTagName('head')[0]
head.appendChild(link)
// 或者
var style= document.createElement('style')
style.type = 'text/css'
style.appendChild(document.createElement('body{background-color:red}'))
var head = document.getElementsByTagName('head')[0]
head.appendChild(style)
三昼伴、操作表格
首先我要贊美一下各大UI框架匾旭,讓我們擺脫了又臭又長的表格操作。
首先我們來看看一個基本的表格是什么樣的
<table>
<tbody>
<tr>
<td>Cell 1圃郊,1</td>
<td>Cell 2价涝,1</td>
</tr>
<tr>
<td>Cell 1,2</td>
<td>Cell 2持舆,2</td>
</tr>
</tbody>
</table>
想一想色瘩,每個元素都要使用DOM.createment()方法生成伪窖,然后再添加到其父元素中,是不是要瘋了居兆!
官方也這么覺得覆山,所以專門為<table>、<tbody>泥栖、<tr>元素添加了一些屬性和方法:
<table>元素的屬性和方法:
1. caption:返回表格的caption元素節(jié)點簇宽,沒有則返回null;
2. tHead, tBodies, tFoot: 返回表格<thead>, <tbody>, <tfoot>元素吧享;
3. rows: 返回元素所有行<tr>元素的HTMLCollection;
4. createTHead(), createTFoot(), createCaption(): 創(chuàng)建<thead>, <tfoot>, <caption>空元素魏割,
將其放到表格中,返回創(chuàng)建的<thead>, <tfoot>, <caption>元素節(jié)點钢颂;
5. deleteTHead(), deleteTFoot(), deleteCaption(): 刪除<thead>, <tfoot>, <caption>空元素钞它,
無返回值(或返回值為undefined)
6. deleteRow(pos): 刪除指定位置(注意參數(shù)不是索引,而是從0開始的位置)的行殊鞭,返回undefined;
7. insertRow(pos): 向rows集合中的指定位置(不是索引)插入一行须揣;
<tbody>元素的屬性和方法:
1. rows: 返回<tbody>元素下所有行<tr>元素的HTMLCollection;
2. deleteRow(pos): 刪除指定位置(注意參數(shù)不是索引,而是從0開始的位置)的行钱豁,返回undefined;
3. insertRow(pos):向rows集合中的指定位置(不是索引)插入一行耻卡;
<tr>元素的屬性和方法:
1. cells: 返回<tr>元素中單元格的HTMLCollection;
2. deleteCell(pos): 刪除指定位置(不是索引)的單元格;
3. insertCell(pos): 向cells集合中的指定位置(不是索引)插入一個單元格牲尺,返回對新插入單元格的引用卵酪;
雖然簡化了表格操作,但還是很麻煩谤碳,大伙留個印象即可溃卡,用到的時候再來看看。