前言
ECMAScript,描述了該語言的語法和基本對(duì)象,如類型、運(yùn)算、流程控制、面向?qū)ο?、異常等?/p>
文檔對(duì)象模型(DOM),描述處理網(wǎng)頁內(nèi)容的方法和接口。
瀏覽器對(duì)象模型(BOM),描述與瀏覽器進(jìn)行交互的方法和接口。
DOM/BOM架構(gòu)
概述
JavaScript運(yùn)行在瀏覽器
BOM就是連接JavaScript代碼和瀏覽器的橋梁,而DOM就是用來操作各種標(biāo)簽元素的。
- BOM包括 window、history、location、document ...
-
DOM包括 Document(整個(gè)文檔)、Element(標(biāo)簽元素)、CharacterData(字符數(shù)據(jù))、Attr(屬性),這些元素又可以繼續(xù)往下劃分。
Document 又可以分為HTMLDocument(就是我們定義的html文件)和XMLDocument(XML文件,安卓會(huì)用,前端用不到)
Element 可以劃分為 HTMLElement(表示 HTML 中的一個(gè)元素,比如div),HTMLElement又可以劃分為HTMLDIvElement 和 HTMLImageElement 故名思義
CharacterData 可以劃分為text(text標(biāo)簽)和Comment(注釋)
Attr 可以理解我們?cè)氐?strong>class屬性id屬性以及值
繼承關(guān)系
- 其中DOM元素、window對(duì)象都繼承自EventTarget,所以它們都有EventTarget上的實(shí)例方法而document是HTMLDocument的實(shí)例對(duì)象
- 所以window上是可以綁定事件,監(jiān)聽事件,分發(fā)事件的
- 其中DOM 中的所有元素節(jié)點(diǎn)都繼承自EventTarget接口,所以DOM中任意節(jié)點(diǎn)可以綁定事件,監(jiān)聽事件,分發(fā)事件
我們可以在瀏覽器中打印它的原型屬性
通過下圖我們可以看出,window繼承Window,Window繼承自EventTarget
通過下圖我們可以看出,document繼承HtmlDocument,HtmlDocument繼承自Document,Document繼承自Node節(jié)點(diǎn),Node節(jié)點(diǎn)繼承自EventTarget
順便說一句:EventTarget繼承自O(shè)bject,Object繼承自null
EventTarget 接口
EventTarget 是一個(gè) DOM 接口,由可以接收事件、并且可以創(chuàng)建偵聽器的對(duì)象實(shí)現(xiàn)。
Element,document 和 window 是最常見的 event targets
EventTarget有三個(gè)原型方法,在window和DOM元素上都可以使用
addEventListener 給元素綁定事件
removeEventListener 移除元素綁定的事件
dispatchEvent 派發(fā)事件
BOM
認(rèn)識(shí)BOM
- JavaScript有一個(gè)非常重要的運(yùn)行環(huán)境就是瀏覽器,而且瀏覽器本身又作為一個(gè)應(yīng)用程序需要對(duì)其本身進(jìn)行操作,所以通常瀏覽器會(huì)有對(duì) 應(yīng)的對(duì)象模型(BOM,Browser Object Model)。
-
BOM主要包括一下的對(duì)象模型:
window:包括全局屬性、方法,控制瀏覽器窗口相關(guān)的屬性、方法;
location:瀏覽器連接到的對(duì)象的位置(URL);
history:操作瀏覽器的歷史;
document:當(dāng)前窗口操作文檔的對(duì)象;
-
window對(duì)象在瀏覽器中有兩個(gè)身份:
身份一:全局對(duì)象。我們知道ECMAScript其實(shí)是有一個(gè)全局對(duì)象的,這個(gè)全局對(duì)象在Node中是global;在瀏覽器中就是window對(duì)象;
身份二:瀏覽器窗口對(duì)象。作為瀏覽器窗口時(shí),提供了對(duì)瀏覽器操作的相關(guān)的API;
Window全局對(duì)象
在瀏覽器中,window對(duì)象就是之前經(jīng)常提到的全局對(duì)象
- 比如在全局通過var聲明的變量,會(huì)被添加到全局環(huán)境變量中,也就是會(huì)被添加到window上;
- 比如window默認(rèn)給我們提供了全局的函數(shù)和類:setTimeout、Math、Date、Object等;
var message = 'hello'
function foo(){
console.log("foo")
}
console.log(window.message)
window.foo()
window.setTimeout(()=>{
console.log('setTimout')
})
const obj = new window.Object()
console.log(obj)
Window窗口對(duì)象
window是一個(gè)復(fù)雜的大對(duì)象,包含了大量的對(duì)象和方法
第一:包含大量的屬性,localStorage、console、location、history、screenX、scrollX等等(大概60+個(gè)屬性);
第二:包含大量的方法,alert、close、scrollTo、open等等(大概40+個(gè)方法);
第三:包含大量的事件,focus、blur、load、hashchange等等(大概30+個(gè)事件);
第四:包含從EventTarget繼承過來的方法,addEventListener、removeEventListener、dispatchEvent方法;
參考地址:MDN文檔:developer.mozilla.org/zh-CN/docs/…
[圖片上傳失敗...(image-bb8cd9-1676958099638)]
常見的屬性
// screenX和screenY屬性返回窗口相對(duì)于屏幕的X和Y坐標(biāo)。
console.log(window.screenX)
console.log(window.screenY)
// 監(jiān)聽滾動(dòng)
window.addEventListener("scroll", () => {
console.log(window.scrollX, window.scrollY)
})
// 獲取窗口的寬度與高度:
console.log(window.outerHeight)
console.log(window.innerHeight)
常見的方法
const scrollBtn = document.querySelector("#scroll")
scrollBtn.onclick = function() {
//1.scrollTo
window.scrollTo({ top: 2000 })
//2.close
window.close()
// 3.open
window.open("http://www.baidu.com", "_self")
}
常見的事件
// 整個(gè)頁面以及所有資源加載完成
window.onload = function() {
console.log("window窗口加載完畢~")
}
window.onfocus = function() {
console.log("window窗口獲取焦點(diǎn)~")
}
window.onblur = function() {
console.log("window窗口失去焦點(diǎn)~")
}
//hash 改變
const hashChangeBtn = document.querySelector("#hashchange")
hashChangeBtn.onclick = function() {
location.hash = "aaaa"
}
window.onhashchange = function() {
console.log("hash發(fā)生了改變")
}
Navigator 對(duì)象
Navigator 對(duì)象包含有關(guān)瀏覽器的信息。到底提供哪些信息很大程度取決于用戶的瀏覽器,但是也有一些公共的屬性,如userAgent 存在所有的瀏覽器中
Navigator 對(duì)象常見的屬性
window.navigator.appCodeName
//返回瀏覽器的代碼名 'Mozilla'
window.navigator.appName
//返回瀏覽器的名稱 'Netscape'
window.navigator.appVersion
//返回瀏覽器的平臺(tái)和版本信息
//'5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
window.navigator.cookieEnabled
//返回指明瀏覽器中是否啟用 cookie 的布爾值 true
window.navigator.platform
//返回運(yùn)行瀏覽器的操作系統(tǒng)平臺(tái) 'MacIntel'
window.navigator.userAgent
//返回由客戶機(jī)發(fā)送服務(wù)器的user-agent 頭部的值
//'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36'
使用場(chǎng)景
檢測(cè)插件
可以檢測(cè)瀏覽器內(nèi)是否安裝了特定的插件
navigator.plugins
判斷系統(tǒng)類型,版本信息
location對(duì)象
location 對(duì)象 是最有用的BOM對(duì)象之一
它既是window對(duì)象的屬性,也是document對(duì)象的屬性,window.location 和document.location引用的是同一個(gè)對(duì)象。
常見屬性
- href: 當(dāng)前window對(duì)應(yīng)的超鏈接URL, 整個(gè)URL;
- protocol: 當(dāng)前的協(xié)議;
- host: 主機(jī)地址;
- hostname: 主機(jī)地址(不帶端口);
- port: 端口;
- pathname: 路徑;
- search: 查詢字符串;
- hash: 哈希值;
- username:URL中的username(很多瀏覽器已經(jīng)禁用);
- password:URL中的password(很多瀏覽器已經(jīng)禁用);
常用方法
- assign:賦值一個(gè)新的URL,并且跳轉(zhuǎn)到該URL中;
- replace:打開一個(gè)新的URL,并且跳轉(zhuǎn)到該URL中(不同的是不會(huì)在瀏覽記錄中留下之前的記錄);
- reload:重新加載頁面,可以傳入一個(gè)Boolean類型;如果把該方法的參數(shù)設(shè)置為 true,那么無論文檔的最后修改日期是什么,它都會(huì)繞過緩存,從服務(wù)器上重新下載該文檔。
location.assign("http://www.baidu.com")
location.
location.replace("http://www.baidu.com")
location.reload(false)
Screen對(duì)象
在編程中使用不多,只用來表明客戶端的能力,其中包括瀏覽器窗口外部的顯示器的信息,如像素的寬度和高度,每個(gè)瀏覽器的screen對(duì)象都包含著不同的屬性。根據(jù)具體業(yè)務(wù)場(chǎng)景去查詢就好。
history 對(duì)象
history對(duì)象允許我們?cè)L問瀏覽器曾經(jīng)的會(huì)話歷史記錄。
history對(duì)象有兩個(gè)屬性
- length:會(huì)話中的記錄條數(shù);
- state:當(dāng)前保留的狀態(tài)值;
history對(duì)象有五個(gè)方法:
- back():返回上一頁,等價(jià)于history.go(-1);
- forward():前進(jìn)下一頁,等價(jià)于history.go(1);
- go():加載歷史中的某一頁;
- pushState():打開一個(gè)指定的地址;
- replaceState():打開一個(gè)新的地址,并且使用replace;
總結(jié)
BOM 以window對(duì)象為依托,表示瀏覽器窗口以及頁面可見區(qū)域
DOM
document Object Model 文檔對(duì)象模型
節(jié)點(diǎn)層次
DOM可以把任何HTML和XML文檔描繪成一個(gè)由多層節(jié)點(diǎn)構(gòu)成的樹形結(jié)構(gòu)。
<html>
<head>
<meta charset="UTF-8">
<title>測(cè)試</title>
</head>
<body>
<h1>標(biāo)題</h1>
<ul>
<1i>
<a href="#">鏈接</a>
</1i>
</ul>
</body>
</html>
上圖中就包括DOM的主要節(jié)點(diǎn)
Document文檔節(jié)點(diǎn)
表示整個(gè) HTML 頁面(相當(dāng)于 document 對(duì)象)
當(dāng)需要訪問任何標(biāo)簽、屬性或文本時(shí),都可以通過文檔節(jié)點(diǎn)進(jìn)行導(dǎo)航
Element元素節(jié)點(diǎn) ul h1 li
表示 HTML 頁面中的標(biāo)簽(即 HTML 頁面的結(jié)構(gòu))
當(dāng)訪問 DOM 樹時(shí),需要從查找元素節(jié)點(diǎn)開始
Attr 屬性節(jié)點(diǎn) href
表示 HTML 頁面中的開始標(biāo)簽包含的屬性
Text 文本節(jié)點(diǎn) 比如title的內(nèi)容
Node 類型
所有的DOM節(jié)點(diǎn)類型都繼承自Node接口,每個(gè)節(jié)點(diǎn)都有一個(gè)nodeType屬性,用于表明節(jié)點(diǎn)的類型。
對(duì)于HTML文檔,節(jié)點(diǎn)主要有以下六種類型:Document節(jié)點(diǎn)、DocumentType節(jié)點(diǎn)、Element節(jié)點(diǎn)、Attribute節(jié)點(diǎn)、Text節(jié)點(diǎn)和DocumentFragment節(jié)點(diǎn)。
分類
| 節(jié)點(diǎn) | 名稱 | 含義 |
|---|---|---|
| Document | 文檔節(jié)點(diǎn) | 整個(gè)文檔(window.document) |
| DocumentType | 文檔類型節(jié)點(diǎn) | 文檔的類型(比如 'DOCTYPE html') |
| Element | 元素節(jié)點(diǎn) | HTML元素(比如body、a等) |
| Attribute | 屬性節(jié)點(diǎn) | HTML元素的屬性(比如class="right") |
| Text | 文本節(jié)點(diǎn) | HTML文檔中出現(xiàn)的文本 |
| DocumentFragment | 文檔碎片節(jié)點(diǎn) | 文檔的片段 |
常用屬性
Node 有幾個(gè)非常用且重要的屬性
- nodeName:node節(jié)點(diǎn)的名稱;
- nodeType:可以區(qū)分節(jié)點(diǎn)的類型;
- nodeValue:node節(jié)點(diǎn)的值;
- childNodes:所有的子節(jié)點(diǎn);
Document 類型
JavaScript 通過Document 類型表示整個(gè)文檔。
Document 類型可以表示 HTML 頁面或者 其他基于 XML 的文檔。不過最常用的應(yīng)用還是作為HTMLDocument實(shí)例的document 對(duì)象。
在瀏覽器中 document 對(duì)象是 HTMLDocument的一個(gè)實(shí)例,表示整個(gè)HTML頁面。而且,document對(duì)象也是window對(duì)象的一個(gè)屬性,因此可以作為全局對(duì)象來訪問。
常見屬性
- document.body 返回文檔的body元素
- document.title 返回當(dāng)前文檔的標(biāo)題
- document.head 返回當(dāng)前文檔的head內(nèi)容
- document.children[0] 返回當(dāng)前文檔html內(nèi)容
常見方法
- 創(chuàng)建元素
- 獲取標(biāo)簽元素
// 創(chuàng)建元素
const imageEl = document.createElement("img")
const imageEl2 = new HTMLImageElement()
// 獲取元素
const divEl1 = document.getElementById("box")
const divEl2 = document.getElementsByTagName("div")
const divEl3 = document.getElementsByName("title")
- 文檔寫入
將輸出流寫入到網(wǎng)頁的能力。
document.write()
document.writeln()
document.open()
document.close()
Element 類型
Element 類型用于表現(xiàn)XML和HTML元素,提供了對(duì)元素標(biāo)簽名,子節(jié)點(diǎn)及特性的訪問
我們平時(shí)創(chuàng)建的div、p、span等元素在DOM中表示為Element元素
常見屬性
- 子元素 children childNodes
- tagName
- id/class
- clientWidth/clientHeight
- clientLeft/clientTop
- offsetLeft/offsetTop
常見方法
獲取特性 getAttribute 修改某個(gè)特性 setAttribute
創(chuàng)建元素 document.createElement()
Text 類型
文本節(jié)點(diǎn)由Text類型表示,包含的是可以照字面解釋的純文本內(nèi)容
- 創(chuàng)建文本節(jié)點(diǎn):document.createTextNode()
Comment 類型
注釋
DocumentFragment 類型
DOM規(guī)定文檔片段是一種輕量級(jí)的文檔,不會(huì)像完整的文檔那樣占有額外的資源
可以在里面保存將來會(huì)添加到文檔的節(jié)點(diǎn)。要?jiǎng)?chuàng)建文檔片段,可以使用document.createDocumentFragment()
文檔片段本身永遠(yuǎn)不會(huì)成為文檔樹的一部分
Attr類型
元素的特性在DOM中用Attr類型來表示。很少使用。
總結(jié)
DOM1級(jí)將HTML和XML文檔看作一個(gè)層次化的節(jié)點(diǎn)樹,方便js來直接操作。
DOM 是由各種節(jié)點(diǎn)構(gòu)成的
- 最基本節(jié)點(diǎn)是Node,所有的節(jié)點(diǎn)都繼承自Node
- Document 表示整個(gè)文檔
- Element 表示文檔中的HTML 或者XML 元素
DOM擴(kuò)展
對(duì)DOM的擴(kuò)展主要包括 選擇符API 和 HTML5
選擇符API
選擇符,最核心的兩個(gè)API 就是 querySelector() 和 querySelectorAll()
可以通過Document 和 Element 類型的實(shí)例調(diào)用
const divEl1 = document.querySelector(".content")
const divEl2 = document.querySelectorAll(".content")
HTML5
html5涉及的面非常廣,我們這里這討論與DOM 節(jié)點(diǎn)相關(guān)的內(nèi)容
獲取dom元素
- getElementsByClassName() 可以通過document 對(duì)象和所有HTML元素調(diào)用該方法,查詢一個(gè)或者包含類名的字符串
自定義數(shù)據(jù)屬性
可以為元素添加非標(biāo)準(zhǔn)的屬性,但是要添加前綴 data-
通過元素的 dataset 屬性來訪問自定義的屬性的值
<div id ="myDiv" data-appId = "12345" data-name="yz"></div>
var div = document.getElementById('myDiv')
var appId = div.dataset.appId
var name = div.dataset.name
插入標(biāo)記
innerHTML屬性
- 可以獲取調(diào)用元素的所有子節(jié)點(diǎn)對(duì)應(yīng)的html片段
- 可以是根據(jù)指定的值創(chuàng)建DOM樹,替換原有的元素節(jié)點(diǎn)
一般我們插入大量新HTML標(biāo)記時(shí),使用innerHTML 與通過多次DOM操作先創(chuàng)建節(jié)點(diǎn)再指定它們之間的關(guān)系相比,效率更高,因?yàn)樵谠O(shè)置innerHTML 時(shí)就會(huì)先創(chuàng)建一個(gè)HTML解析器,這個(gè)解析是在瀏覽器級(jí)別的基礎(chǔ)上代碼(c++)運(yùn)行的,因此比執(zhí)行js 快得多,當(dāng)然也會(huì)帶來 創(chuàng)建銷毀 html 解析器也有性能消耗。所以控制次數(shù)。
DOM2和DOM3
DOM1級(jí)主要定義的是HTML和XML文檔的底層結(jié)構(gòu)
DOM2級(jí)和DOM3級(jí)是在這個(gè)結(jié)構(gòu)基礎(chǔ)上引入了更多的交互能力和特性。擴(kuò)展了DOM API,以滿足操作DOM的所有需求,同時(shí)提供更好的錯(cuò)誤處理和特性監(jiān)測(cè)能力
DOM變化
- Node 類型 Document 類型 Element 類型 增加了命名空間的概念
- DOM3引入 兩個(gè)輔助比較節(jié)點(diǎn)的方法 isSameNode() 和 isEqualNode( )
- 一個(gè)判斷相同 兩個(gè)節(jié)點(diǎn)引用的是同一個(gè)對(duì)象
- 一個(gè)判斷相等 兩個(gè)節(jié)點(diǎn)是同類型的對(duì)象,具有相等的屬性(nodeName,nodeValue等等),而且他們的attributes和 childNodes屬性也相等(相同位置包含相同的)
var div1 = document.createElement("div")
div1.setAttribute("class","box")
var div1 = document.createElement("div")
div1.setAttribute("class","box")
alert(div1.isSameNode(div1)) // true
alert(div1.isEqualNode(div1)) // true
alert(div1.isSameNode(div2)) // false
- iframe中的文檔對(duì)象可以通過contentDocument 訪問 所有瀏覽器都支持
var iframe = document.getElementById("myIframe")
var iframe = iframe.contentDocuemnt || iframe.contentWindow.document
樣式變化
訪問元素的樣式
- 新增style屬性 可以通過style對(duì)象訪問所有樣式信息,也可以進(jìn)行修改
- document.default.getComputedStyle(dom) 可以返回整個(gè)dom的樣式
操作樣式表
- 大多數(shù)情況下,使用style屬性就可以滿足所有操作樣式柜子的需求
元素大小
- 偏移量
- offsetHeight offsetWdith offsetLeft offsetTop
- 可以通過以上四個(gè)屬性計(jì)算
- 客戶區(qū)大小
- clientHeight clientWidth
- 滾動(dòng)大小
- scrollHeight scrollWidth scrollLeft scrollTop
- scrollLeft scrollTop可以用來確定當(dāng)前元素滾動(dòng)狀態(tài)
-
確定元素大小
- getBoundClientRect()返回一個(gè)矩形對(duì)象,包含四個(gè)屬性 left top right bottom,給出了元素在頁面中相對(duì)于視口的位置。
- top/y:元素上邊到視窗上邊的距離;
- right:元素右邊到視窗左邊的距離;
- bottom:元素下邊到視窗上邊的距離;
- left/x:元素左邊到視窗左邊的距離;
- width:元素的寬度;
- height:元素的高度;
范圍
為了讓開發(fā)人員更方便得控制頁面,dom2 定義了范圍 range接口。
document.createRange()
- 用dom范圍實(shí)現(xiàn)簡(jiǎn)單選擇
var range1 = document.createRange()
var p1 = document.getElementById('p1')
range1.selcetNode(p1)
- 也可以操作修改dom范圍中的內(nèi)容
小結(jié)
dom2 級(jí)主要新增了操作樣式的能力和操作范圍內(nèi)dom的能力
總結(jié)
對(duì)于dom和bom的學(xué)習(xí),我所秉持的觀點(diǎn)依然是,抓大放小,建立知識(shí)體系,常用的api可以了解,不常用的api知道去哪里查就好,因?yàn)槠匠I(yè)務(wù)開發(fā)也接觸不到太底層的代碼。
框架發(fā)展到今天,對(duì)我們前端開發(fā)來說,已經(jīng)很少去操作Dom了,但框架已經(jīng)幫助我們做了,對(duì)于Bom的交互也有很多封裝成熟的函數(shù)庫,但是如果要對(duì)前端深入學(xué)習(xí),我覺得這些知識(shí)還是必須掌握的,前端學(xué)習(xí)js 永遠(yuǎn)是基礎(chǔ),框架函數(shù)庫,都是錦上添花的東西。
我們要知其然,更要知其所以然。