一沈矿、DOM
1畅买、定義
DOM,即文檔對象模型(Document Object Model )
2细睡、現(xiàn)象
通過在頁面——打開:檢查元素——看見:元素為可折疊谷羞。可選中頁面對應(yīng)元素,事實上即選擇了對象(即也選擇了對象對應(yīng)的屬性或方法),相當(dāng)于把頁面文檔對象化傍衡。事實上,就是用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):
3挠阁、 document.compatMode
document.compatMode
compatMode 屬性 返回瀏覽器處理文檔的模式宾肺,可能的值為
- BackCompat:向后兼容模式溯饵,也就是沒有添加DOCTYPE
- CSS1Compat:嚴格模式,添加了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)先從本地緩存重新加載(默認值)
document.location.reload(false)
// 跳轉(zhuǎn)到另一個網(wǎng)址啄巧,但當(dāng)前文檔不保留在history對象中,
// 即無法用后退按鈕跪者,回到當(dāng)前文檔
document.location.assign('http://www.google.com')
// 將location對象轉(zhuǎn)為字符串棵帽,等價于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é)點還是會繼續(xù)加載。
-做測試時怀偷,無須使用document.write( )方法
三家厌、Element對象,屬性(或方法)
document對應(yīng)的具體元素應(yīng)如何選茸倒ぁ(或操作)饭于?
element對象表示頁面上的元素。使用JS選擇頁面上的元素(element)维蒙,然后對其做操作掰吕。
那么,對頁面元素的操作有哪些颅痊?
A畴栖、選擇它:通過一些方法找到其具體元素(如用css的id,class名八千,選擇器吗讶、鄰居燎猛、賦值等)
B、處理它:對擁有類型為元素節(jié)點照皆、文本節(jié)點重绷、注釋節(jié)點的子節(jié)點進行刪除、增加膜毁、查找昭卓、修改等操作
1、幾個常用屬性
nodeName:元素標簽名瘟滨,還有個類似的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()
頁面元素中不止獨一無二的id名倒淫,還有類選擇器,當(dāng)我們在頁面控制臺上通過getElementByClassName( )時败玉,可獲鹊型痢(或查詢)到一個或多個類選擇器,會出現(xiàn)如圖現(xiàn)象:
這看上去有點像數(shù)組运翼,呈現(xià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格式的對象,不會實時反映元素的變化庞瘸。如:
(4)假設(shè),類選擇器有嵌套的話捧弃,我們?nèi)绾潍@取嵌套于內(nèi)的元素?如圖:
A、(較為繁瑣的) ES3寫法:getElementsByName( ).getElementsByName( )
語法:
document.getElementsByName().getElementsByName()
例子:
document.getElementsByClassName('box')[0].getElementsByClassName('child')
--> HTMLCollection [div.child]
事實上违霞,使用document.getElementsByName()做一個聯(lián)集嘴办,即無論是document還是任何一個對象,都可以使用:對象.XXXX 去做一個聯(lián)集對象去獲取相對應(yīng)的準確元素买鸽。
B涧郊、(較為簡便的)ES5寫法:querySelector()
注:可用于選擇id元素使用
語法:
document.querySelector()
例子:
document.querySelector('.box .child')
--> <div class="child">child</div>
不過,它選擇元素的時候眼五,只能獲取一個元素妆艘,如頁面元素中有多個div,只會默認選擇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()
此方法返回所有指定標簽的元素(搜索范圍包括本身)逗物,返回值是一個HTMLCollection對象搬卒,也就是說瑟俭,搜索結(jié)果是一個動態(tài)集合,任何元素的變化都會實時反映在返回的集合中契邀。如圖:
3摆寄、創(chuàng)建元素
(1)createElement() 創(chuàng)建一個新的元素放到頁面上
用此方法創(chuàng)建并傳入html的元素標簽,創(chuàng)建一個虛擬的dom坯门。該dom的節(jié)點存在內(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)元素標簽還不夠,我們可通過createTextNode( )去創(chuàng)建(或生成)一個文本现恼,將文本的內(nèi)容放入元素中肃续,如:
var text = document.createTextNode('wangxiaoqin')
--> undefined
text
--> "wangxiaoqin"
(3)createDocumentFragment()
該方法用來生成一個存在于內(nèi)存的dom片段,但不屬于當(dāng)前文檔叉袍。即不會生成一個標簽始锚,虛擬生成,常用于生成復(fù)雜的dom結(jié)構(gòu)喳逛,然后插入當(dāng)前文檔瞧捌。
正因為它不屬于當(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"
看一個實例:
<!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)建一個虛擬的片段乔夯,可看成是一個虛擬標簽,到最后放在navbarNode款侵,該虛擬標簽消失
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)建的這個虛擬片段甲脏,我們可看成是一個虛擬標簽,到最后放在navbarNode妹笆,該虛擬標簽消失块请。并不影響實際頁面元素的改動。
假設(shè):我們在createDocumentFragment() 里加上一個實際的塊元素包裹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é)點海渊。
方法有一個布爾值參數(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')
頁面范例展示涉及到的點:
(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')
//可以獲取(或添加)它的id
link.getAttribute('id')
//可以刪除它的id
link.removeAttribute('id')
圖:
(2)創(chuàng)建一個樣式放在頁面上肥哎,如何操作辽俗?
如:使用js讓我們的頁面上引入一個新的js,如jquery篡诽⊙缕可先在Bootstrap 中文網(wǎng)開源項目免費 CDN 加速服務(wù)上找一個jquery的地址
分析:用js引用一個jQuery,那么需要有一個scirpt的標簽杈女,用src來指向jQuery地址
//創(chuàng)建一個script標簽
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
//驗證一下
script
--> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script >
//通過.body.appendChild(script)將整個標簽屬性值放置到頁面
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é)點的方式appendChild進去)
頁面的一些菜單欄設(shè)置翰蠢,通過后臺要數(shù)據(jù),后臺交還一個數(shù)組或json數(shù)據(jù)(包括菜單的所有信息)啰劲,如何將菜單渲染到頁面上梁沧?通過字符串操作遍歷對象(或數(shù)組)去拼裝html字符串,拼接后一次性將html放置在空的節(jié)點下呈枉,則頁面看到了東西
幾個操作: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è)置的元素標簽下文本是什么(或設(shè)置它的文本)
注:沒有必要再創(chuàng)建什么元素標簽,只需要設(shè)置一個空標簽砚殿,然后設(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é)點上的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屬性,而是元素計算后的樣式(包括其他地方做的設(shè)置、瀏覽器默認樣式谆甜、繼承樣式等綜合后的結(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改淑,但這樣比較細,且復(fù)雜浴讯。假設(shè)當(dāng)我們在頁面點擊一個按鈕時溅固,整體發(fā)生一個很大的變化(包括字體大小、出現(xiàn)的邊框兰珍、背景色侍郭、背景圖片,甚至動畫效果)掠河,如果都是用style來操作亮元,或?qū)е麓a冗長難修改,
我們可以將這些樣式放在一個css的class里面唠摹,如active爆捞。正常情況下是沒有這些class,當(dāng)我們點擊某個元素的時候勾拉,即鼠標放上去時煮甥,給這個元素添加一個class
var nodeBox = document.querySelector('.box')
console.log( nodeBox.classList ) //通過選擇元素nodeBox去看看classList里擁有哪些class,
//即得到一個類數(shù)組對象.通過下標的方式獲取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双霍、頁面寬高的計算
(1)element.clientHeight VS element.clientWidth
獲取元素窗口的高度、寬度
(2)element.offsetHeight VS element.offsetWidth
獲扰(包含邊框+內(nèi)邊距+窗口整體)的高度洒闸、寬度
獲取兩種的寬高,得到的結(jié)果看具體情況均芽,有些時候是相同丘逸,有些時候是不同,如圖:
(3)element.scrollHeight
元素滾動內(nèi)容的總長度掀宋,也分實際情況
假設(shè)頁面上有一處包含內(nèi)容的div塊級深纲,頁面若為可滾動的羞反,表示內(nèi)容長度超出它容器的高度,而容器高度已為固定寬高囤萤,此時scrollHeight>clientHeight
若頁面若無滾動條昼窗、父容器高度沒有固定,則scrollHeight=clientHeight=offsetHeight
(4)element.scrollTop
獲取元素滾動的高度涛舍,即滾動時滾動了一定的值
document.body.scrollTop
(5)window.innerHeight
窗口的高度
window.innerHeigh
實例操作:http://js.jirengu.com/fuser/1/edit?html,css
以下問題跟之后的解決懶加載有密切聯(lián)系
問題1:如何去判斷一個元素是否出現(xiàn)在窗口的視野中
問題2:如何判斷頁面滾動到底部
元素到頂點的值=滾動的值
元素滾動的距離+窗口的高度=這個元素到頂點的距離