javascrip高級(jí)前端開(kāi)發(fā)常用的幾個(gè)API示例詳解
MutationObserver
MutationObserver 是一個(gè)可以監(jiān)聽(tīng) DOM 結(jié)構(gòu)變化的接口。
當(dāng) DOM 對(duì)象樹(shù)發(fā)生任何變動(dòng)時(shí),MutationObserver 會(huì)得到通知。
API
MutationObserver 是一個(gè)構(gòu)造器,接受一個(gè) callback 參數(shù),用來(lái)處理節(jié)點(diǎn)變化的回調(diào)函數(shù),返回兩個(gè)參數(shù):
mutations:節(jié)點(diǎn)變化記錄列表(sequence<MutationRecord>)
observer:構(gòu)造 MutationObserver 對(duì)象。
MutationObserver 對(duì)象有三個(gè)方法,分別如下:
observe:設(shè)置觀察目標(biāo),接受兩個(gè)參數(shù),target:觀察目標(biāo),options:通過(guò)對(duì)象成員來(lái)設(shè)置觀察選項(xiàng)
disconnect:阻止觀察者觀察任何改變
takeRecords:清空記錄隊(duì)列并返回里面的內(nèi)容
//選擇一個(gè)需要觀察的節(jié)點(diǎn)
var targetNode = document.getElementById('root')
// 設(shè)置observer的配置選項(xiàng)
var config = { attributes: true, childList: true, subtree: true }
// 當(dāng)節(jié)點(diǎn)發(fā)生變化時(shí)的需要執(zhí)行的函數(shù)
var callback = function (mutationsList, observer) {
for (var mutation of mutationsList) {
if (mutation.type == 'childList') {
console.log('A child node has been added or removed.')
} else if (mutation.type == 'attributes') {
console.log('The ' + mutation.attributeName + ' attribute was modified.')
}
}
}
// 創(chuàng)建一個(gè)observer示例與回調(diào)函數(shù)相關(guān)聯(lián)
var observer = new MutationObserver(callback)
//使用配置文件對(duì)目標(biāo)節(jié)點(diǎn)進(jìn)行觀測(cè)
observer.observe(targetNode, config)
// 停止觀測(cè)
observer.disconnect()
observe 方法中 options 參數(shù)有已下幾個(gè)選項(xiàng):
childList:設(shè)置 true,表示觀察目標(biāo)子節(jié)點(diǎn)的變化,比如添加或者刪除目標(biāo)子節(jié)點(diǎn),不包括修改子節(jié)點(diǎn)以及子節(jié)點(diǎn)后代的變化
attributes:設(shè)置 true,表示觀察目標(biāo)屬性的改變
characterData:設(shè)置 true,表示觀察目標(biāo)數(shù)據(jù)的改變
subtree:設(shè)置為 true,目標(biāo)以及目標(biāo)的后代改變都會(huì)觀察
attributeOldValue:如果屬性為 true 或者省略,則相當(dāng)于設(shè)置為 true,表示需要記錄改變前的目標(biāo)屬性值,設(shè)置了 attributeOldValue 可以省略 attributes 設(shè)置
characterDataOldValue:如果 characterData 為 true 或省略,則相當(dāng)于設(shè)置為 true,表示需要記錄改變之前的目標(biāo)數(shù)據(jù),設(shè)置了 characterDataOldValue 可以省略 characterData 設(shè)置
attributeFilter:如果不是所有的屬性改變都需要被觀察,并且 attributes 設(shè)置為 true 或者被忽略,那么設(shè)置一個(gè)需要觀察的屬性本地名稱(不需要命名空間)的列表
特點(diǎn)
MutationObserver 有以下特點(diǎn):
- 它等待所有腳本任務(wù)完成后才會(huì)運(yùn)行,即采用異步方式
- 它把 DOM 變動(dòng)記錄封裝成一個(gè)數(shù)組進(jìn)行處理,而不是一條條地個(gè)別處理 DOM 變動(dòng)。
- 它即可以觀察發(fā)生在 DOM 節(jié)點(diǎn)的所有變動(dòng),也可以觀察某一類變動(dòng)
當(dāng) DOM 發(fā)生變動(dòng)會(huì)觸發(fā) MutationObserver 事件。但是,它與事件有一個(gè)本質(zhì)不同:事件是同步觸發(fā),也就是說(shuō) DOM 發(fā)生變動(dòng)立刻會(huì)觸發(fā)相應(yīng)的事件;MutationObserver 則是異步觸發(fā),DOM 發(fā)生變動(dòng)以后,并不會(huì)馬上觸發(fā),而是要等到當(dāng)前所有 DOM 操作都結(jié)束后才觸發(fā)。
舉例來(lái)說(shuō),如果在文檔中連續(xù)插入 1000 個(gè)段落(p 元素),會(huì)連續(xù)觸發(fā) 1000 個(gè)插入事件,執(zhí)行每個(gè)事件的回調(diào)函數(shù),這很可能造成瀏覽器的卡頓;而 MutationObserver 完全不同,只在 1000 個(gè)段落都插入結(jié)束后才會(huì)觸發(fā),而且只觸發(fā)一次,這樣較少了 DOM 的頻繁變動(dòng),大大有利于性能。
IntersectionObserver
網(wǎng)頁(yè)開(kāi)發(fā)時(shí),常常需要了解某個(gè)元素是否進(jìn)入了"視口"(viewport),即用戶能不能看到它。
傳統(tǒng)的實(shí)現(xiàn)方法是,監(jiān)聽(tīng)到 scroll 事件后,調(diào)用目標(biāo)元素的 getBoundingClientRect()方法,得到它對(duì)應(yīng)于視口左上角的坐標(biāo),再判斷是否在視口之內(nèi)。這種方法的缺點(diǎn)是,由于 scroll 事件密集發(fā)生,計(jì)算量很大,容易造成性能問(wèn)題。
目前有一個(gè)新的 IntersectionObserver API,可以自動(dòng)"觀察"元素是否可見(jiàn),Chrome 51+ 已經(jīng)支持。由于可見(jiàn)(visible)的本質(zhì)是,目標(biāo)元素與視口產(chǎn)生一個(gè)交叉區(qū),所以這個(gè) API 叫做"交叉觀察器"。
API
IntersectionObserver 是瀏覽器原生提供的構(gòu)造函數(shù),接受兩個(gè)參數(shù):callback 是可見(jiàn)性變化時(shí)的回調(diào)函數(shù),option 是配置對(duì)象(該參數(shù)可選)。
var io = new IntersectionObserver(callback, option)
// 開(kāi)始觀察
io.observe(document.getElementById('example'))
// 停止觀察
io.unobserve(element)
// 關(guān)閉觀察器
io.disconnect()
如果要觀察多個(gè)節(jié)點(diǎn),就要多次調(diào)用這個(gè)方法。
io.observe(elementA) io.observe(elementB)
目標(biāo)元素的可見(jiàn)性變化時(shí),就會(huì)調(diào)用觀察器的回調(diào)函數(shù) callback。callback 一般會(huì)觸發(fā)兩次。一次是目標(biāo)元素剛剛進(jìn)入視口(開(kāi)始可見(jiàn)),另一次是完全離開(kāi)視口(開(kāi)始不可見(jiàn))。
var io = new IntersectionObserver((entries) => {
console.log(entries)
})
callback 函數(shù)的參數(shù)(entries)是一個(gè)數(shù)組,每個(gè)成員都是一個(gè) IntersectionObserverEntry 對(duì)象。舉例來(lái)說(shuō),如果同時(shí)有兩個(gè)被觀察的對(duì)象的可見(jiàn)性發(fā)生變化,entries 數(shù)組就會(huì)有兩個(gè)成員。
time:可見(jiàn)性發(fā)生變化的時(shí)間,是一個(gè)高精度時(shí)間戳,單位為毫秒
target:被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對(duì)象
isIntersecting: 目標(biāo)是否可見(jiàn)
rootBounds:根元素的矩形區(qū)域的信息,getBoundingClientRect()方法的返回值,如果沒(méi)有根元素(即直接相對(duì)于視口滾動(dòng)),則返回 null
boundingClientRect:目標(biāo)元素的矩形區(qū)域的信息
intersectionRect:目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息
intersectionRatio:目標(biāo)元素的可見(jiàn)比例,即 intersectionRect 占 boundingClientRect 的比例,完全可見(jiàn)時(shí)為 1,完全不可見(jiàn)時(shí)小于等于 0
舉個(gè)例子
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
#div1 {
position: sticky;
top: 0;
height: 50px;
line-height: 50px;
text-align: center;
background: black;
color: #ffffff;
font-size: 18px;
}
</style>
</head>
<body>
<div id="div1">首頁(yè)</div>
<div style="height: 1000px;"></div>
<div id="div2" style="height: 100px; background: red;"></div>
<script>
var div2 = document.getElementById('div2')
let observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (element, index) {
console.log(element)
if (element.isIntersecting) {
div1.innerText = '我出來(lái)了'
} else {
div1.innerText = '首頁(yè)'
}
})
},
{
root: null,
threshold: [0, 1]
}
)
observer.observe(div2)
</script>
</body>
</html>
相比于 getBoundingClientRect,它的優(yōu)點(diǎn)是不會(huì)引起重繪回流。
圖片懶加載
圖片懶加載的原理主要是判斷當(dāng)前圖片是否到了可視區(qū)域這一核心邏輯實(shí)現(xiàn)的。這樣可以節(jié)省帶寬,提高網(wǎng)頁(yè)性能。傳統(tǒng)的突破懶加載是通過(guò)監(jiān)聽(tīng) scroll 事件實(shí)現(xiàn)的,但是 scroll 事件會(huì)在很短的時(shí)間內(nèi)觸發(fā)很多次,嚴(yán)重影響頁(yè)面性能。為提高頁(yè)面性能,我們可以使用 IntersectionObserver 來(lái)實(shí)現(xiàn)圖片懶加載。
const imgs = document.querySelectorAll('img[data-src]')
const config = {
rootMargin: '0px',
threshold: 0
}
let observer = new IntersectionObserver((entries, self) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
let img = entry.target
let src = img.dataset.src
if (src) {
img.src = src
img.removeAttribute('data-src')
}
// 解除觀察
self.unobserve(entry.target)
}
})
}, config)
imgs.forEach((image) => {
observer.observe(image)
})
無(wú)限滾動(dòng)
無(wú)限滾動(dòng)(infinite scroll)的實(shí)現(xiàn)也很簡(jiǎn)單。
var intersectionObserver = new IntersectionObserver(function (entries) {
// 如果不可見(jiàn),就返回
if (entries[0].intersectionRatio <= 0) return
loadItems(10)
console.log('Loaded new items')
})
// 開(kāi)始觀察
intersectionObserver.observe(document.querySelector('.scrollerFooter'))
getComputedStyle()
DOM2 Style 在?document.defaultView?上增加了 getComputedStyle()方法,該方法返回一個(gè)?CSSStyleDeclaration
對(duì)象(與 style 屬性的類型一樣),包含元素的計(jì)算樣式。
API
document.defaultView.getComputedStyle(element[,pseudo-element]) // or window.getComputedStyle(element[,pseudo-element])
這個(gè)方法接收兩個(gè)參數(shù):要取得計(jì)算樣式的元素和偽元素字符串(如":after")。如果不需要查詢偽元素,則第二個(gè)參數(shù)可以傳 null。
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#myDiv {
background-color: blue;
width: 100px;
height: 200px;
}
</style>
</head>
<body>
<div id="myDiv" style="background-color: red; border: 1px solid black"></div>
</body>
<script>
function getStyleByAttr(obj, name) {
return window.getComputedStyle ? window.getComputedStyle(obj, null)[name] : obj.currentStyle[name]
}
let node = document.getElementById('myDiv')
console.log(getStyleByAttr(node, 'backgroundColor'))
console.log(getStyleByAttr(node, 'width'))
console.log(getStyleByAttr(node, 'height'))
console.log(getStyleByAttr(node, 'border'))
</script>
</html>
與style的異同
getComputedStyle 和 element.style 的相同點(diǎn)就是二者返回的都是 CSSStyleDeclaration 對(duì)象。而不同點(diǎn)就是:
element.style 讀取的只是元素的內(nèi)聯(lián)樣式,即寫在元素的 style 屬性上的樣式;而 getComputedStyle 讀取的樣式是最終樣式,包括了內(nèi)聯(lián)樣式、嵌入樣式和外部樣式。
element.style 既支持讀也支持寫,我們通過(guò) element.style 即可改寫元素的樣式。而 getComputedStyle 僅支持讀并不支持寫入。我們可以通過(guò)使用 getComputedStyle 讀取樣式,通過(guò) element.style 修改樣式
getBoundingClientRect
getBoundingClientRect() 方法返回元素的大小及其相對(duì)于視口的位置。
API
let DOMRect = object.getBoundingClientRect()
它的返回值是一個(gè) DOMRect 對(duì)象,這個(gè)對(duì)象是由該元素的 getClientRects() 方法返回的一組矩形的集合,就是該元素的 CSS 邊框大小。
返回的結(jié)果是包含完整元素的最小矩形,并且擁有 left, top, right, bottom, x, y, width, 和 height 這幾個(gè)以像素為單位的只讀屬性用于描述整個(gè)邊框。除了 width 和 height 以外的屬性是相對(duì)于視圖窗口的左上角來(lái)計(jì)算的。
應(yīng)用場(chǎng)景
1、獲取 dom 元素相對(duì)于網(wǎng)頁(yè)左上角定位的距離
以前的寫法是通過(guò) offsetParent 找到元素到定位父級(jí)元素,直至遞歸到頂級(jí)元素 body 或 html。
// 獲取dom元素相對(duì)于網(wǎng)頁(yè)左上角定位的距離
function offset(el) {
var top = 0
var left = 0
do {
top += el.offsetTop
left += el.offsetLeft
} while ((el = el.offsetParent)) // 存在兼容性問(wèn)題,需要兼容
return {
top: top,
left: left
}
}
var odiv = document.getElementsByClassName('markdown-body')
offset(a[0]) // {top: 271, left: 136}
現(xiàn)在根據(jù) getBoundingClientRect 這個(gè) api,可以寫成這樣:
var positionX = this.getBoundingClientRect().left + document.documentElement.scrollLeft var positionY = this.getBoundingClientRect().top + document.documentElement.scrollTop
2、判斷元素是否在可視區(qū)域內(nèi)
function isElView(el) {
var top = el.getBoundingClientRect().top // 元素頂端到可見(jiàn)區(qū)域頂端的距離
var bottom = el.getBoundingClientRect().bottom // 元素底部端到可見(jiàn)區(qū)域頂端的距離
var se = document.documentElement.clientHeight // 瀏覽器可見(jiàn)區(qū)域高度。
if (top < se && bottom > 0) {
return true
} else if (top >= se || bottom <= 0) {
// 不可見(jiàn)
}
return false
}
以上就是javascrip高級(jí)前端開(kāi)發(fā)常用的幾個(gè)API示例詳解的詳細(xì)內(nèi)容,更多關(guān)于高級(jí)前端API示例的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
arcgis.js控制地圖地體的顯示范圍超出區(qū)域自動(dòng)彈回(實(shí)現(xiàn)思路)
這篇文章主要介紹了arcgis.js控制地圖地體的顯示范圍超出區(qū)域自動(dòng)彈回,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
兼容IE與firefox火狐的回車事件(js與jquery)
今天看了網(wǎng)上的朋友說(shuō)了,很多網(wǎng)站提供的回車事件代碼都是不兼容firefox的,其實(shí)腳本之家提供的代碼,一直以來(lái)都是盡量的兼容多瀏覽器。2010-10-10
前端傳遞參數(shù)時(shí)form-data和json的區(qū)別詳解
前端可以通FormData對(duì)象實(shí)現(xiàn)表單形式提交數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于前端傳遞參數(shù)時(shí)form-data和json區(qū)別的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
Javascript打印網(wǎng)頁(yè)部分內(nèi)容的腳本
有時(shí)候我們只需要打印部分內(nèi)容,因?yàn)楝F(xiàn)在的頁(yè)面中廣告和一些相關(guān)內(nèi)容很多,所有用下面的方法,就可以了2008-11-11
仿iPhone通訊錄制作小程序自定義選擇組件的實(shí)現(xiàn)
這篇文章主要介紹了仿iPhone通訊錄制作小程序自定義選擇組件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
基于JavaScript+HTML編寫一個(gè)日期選擇插件
在現(xiàn)代Web應(yīng)用程序中,日期選擇器是一個(gè)非常常見(jiàn)的組件,用戶可以使用它來(lái)選擇特定的日期,在本篇文章中,我們將使用JavaScript和HTML來(lái)創(chuàng)建一個(gè)簡(jiǎn)單但功能強(qiáng)大的日期選擇插件,這個(gè)日期選擇插件是比較考驗(yàn)Js基本功的,需要的朋友可以參考下2023-10-10
靈活使用數(shù)組制作圖片切換js實(shí)現(xiàn)
這篇文章主要介紹了靈活使用數(shù)組制作圖片切換效果,js實(shí)現(xiàn)圖片切換特效,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-07-07
artdialog的圖片/標(biāo)題以及關(guān)閉按鈕不顯示的解決方法
正如標(biāo)題所言不顯示的原因是因其它c(diǎn)ss樣式文件中包含div{ overflow:hidden; }引起的artdialog的圖片以及關(guān)閉按鈕不顯示,具體的解決方法如下,感興趣的朋友可以參考下哈2013-06-06
uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn)
在微信小程序中不支持多張圖片上傳,需要做循環(huán)實(shí)現(xiàn)多張圖片上傳,下面這篇文章主要給大家介紹了關(guān)于uni-app使用uploadFile上傳多張圖片的具體實(shí)現(xiàn),需要的朋友可以參考下2023-04-04

