- 做者:陳大魚頭
- github: KRISACHAN
不知道各位童鞋有木有看過 《等待戈多》 這部出名的荒誕戲劇 。其劇情大概就是 戈戈 與 狄狄 等待 戈多 的過程當中發生的一些雜事,一共兩幕。等了這麼多年,也不知道 戈多 如今在哪,赴約了沒有。javascript
若是 戈戈 與 狄狄 像咱們監聽頁面元素變化那樣監聽戈多的動態,是否是就不會出現空歡喜的狀態?是否是就不用等得那麼辛苦?是否是甚至能夠主動去尋找戈多?css
提及監聽頁面元素變化,那麼你可知道有哪些方法能夠實現這個功能?html
關於 Object.defineProperty
這個屬性你們應該很熟(畢竟是各種面經中的常客),但仍是要簡單介紹下~java
Object.defineProperty
容許精確添加或修改對象的屬性。經過賦值操做添加的普通屬性是可枚舉的,可以在屬性枚舉期間呈現出來。git
描述符可同時具備的鍵值:github
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
數據描述符 | Yes | Yes | Yes | Yes | No | No |
存取描述符 | Yes | Yes | No | No | Yes | Yes |
因此咱們有如下這種效果:數組
代碼以下:微信
'use strict'
Object.defineProperty(godot, 'style', {
get() {
return this.getAttribute('style')
},
set(data) {
this.setAttribute('style', data)
const distance = (noLeftTree.offsetLeft - this.offsetLeft)
console.log(distance >= 51 ? '戈多沒來,咱們先各自幹各自的活吧' : '戈多快到了,走,咱們集合去')
}
})
const whereIsGodot = start => {
if (start) {
let d = 0
const godotRun = () => {
if (noLeftTree.offsetLeft - 51 >= d) {
setTimeout(() => {
d++
godot.style = `left: ${d}px`
godotRun()
}, 16)
}
}
godotRun()
}
}
複製代碼
簡單來講就是使用 Object.defineProperty
監聽戈多的位置變化,而後當戈多移動到集合地點附近時,等待戈多的倆哥們就能夠去赴約了。經過上述的代碼,咱們能夠知道 whereIsGodot
函數只負責戈多的位置移動,可是監聽權在等待戈多的兩我的那裏,這樣保證了代碼語義化的同時,耦合度也儘量地小。dom
Mmmmm,我一直覺得 MutationObserver
是個新屬性,直到我膝蓋中了一箭看了can i use 。函數
原本魚頭我也不知道有這屬性,可是最近在工做上遇到了須要監聽頁面元素變更的場景,而後就瞭解到了這個API。
因而魚頭便看了文檔,發現是個好牛逼的API。
簡單來講就是一個能夠監聽 DOM Tree 變更的API,名字直譯就是 「突變觀察者」 。
按WHATWG的定義,它的執行邏輯以下:
突變觀察者 是個構造器,它接受一個回調並返回一個 節點記錄列表(sequence <MutationRecord>
) 以及 構造的參數對象(MutationObersver)。
它有如下三個方法:
options選項可選參數(如下屬性可設置爲true):
下面咱們就經過實際的代碼來監聽戈多的位置變化。
效果仍是如同上圖。
代碼以下:
const godot = document.querySelector('#godot')
const config = {
childList: true,
attributes: true,
characterData: true,
subtree: true,
attributeOldValue: true,
characterDataOldValue: true
}
const mutationCallback = mutationsList => {
const [
{
target: {
offsetLeft: godotPos
}
}
] = mutationsList
const distance = (noLeftTree.offsetLeft - godotPos)
console.log(distance >= 51 ? '戈多沒來,咱們先各自幹各自的活吧' : '戈多快到了,走,咱們集合去')
}
const observer = new MutationObserver(mutationCallback)
observer.observe(godot, config)
const whereIsGodot = start => {
if (start) {
let d = 0
const godotRun = () => {
if (noLeftTree.offsetLeft - 51 >= d) {
setTimeout(() => {
d++
godot.style = `left: ${d}px`
godotRun()
}, 16)
} else {
observer.disconnect()
}
}
godotRun()
}
}
複製代碼
由於魚頭在業務須要對某個已經完善的功能在部分操做監聽數據變更,若是對原來的代碼進行改動,也不是一件輕鬆的事,並且這樣子代碼太冗長,耦合度也會較高,因此就選擇了用 突變觀察者 來實現,效果仍是不錯的。
除了監聽元素的變更,還有什麼方式能夠知道戈多的位置呢?
若是有那就是 Intersection Observer 了。
戈多心想:「又來一個Observer ?別監聽了,我去找大家就是了,嚶嚶嚶。 」
IntersectionObserver
直譯是 「交叉觀察者」 ,這個API使開發人員可以監聽目標元素與根(祖先或視口)元素交叉狀態的方法。
它的用法跟 MutationObserver
類似,一樣是個構造器,它接受一個 回調函數(callback(entries)) 以及 可選參數對象(options) 。
首先 callback 會返回一個 監聽屬性對象(IntersectionObserverEntry) ,其具體屬性以下:
getBoundingClientRect()
的值,沒有則返回 null
;intersectionRect / boundingClientRect
徹底可見時爲1,徹底不可見時小於等於0;options 可選參數以下:
margin
同樣,發生交叉的偏移量;可選擇方法以下:
IntersectionObserver
中止監聽特定目標元素。因此怎麼用這個API來監聽戈多的位置呢?
先看效果(真特麼簡陋)
代碼以下:
<style> * { margin: 0; padding: 0; box-sizing: border-box; } html, body { width: 100%; height: 200%; } noLeftTree { position: fixed; left: 0; top: 0; width: 100%; height: 100px; background: #FFF; } godot, estragon, vladimir { position: absolute; width: 50px; height: 50px; border-radius: 50%; border: 1px solid; text-align: center; } estragon { top: 0; left: 0; } vladimir { top: 0; right: 0; } godot { left: calc(50% - 25px); top: 1000px; } </style>
<noLeftTree id="noLeftTree">
<estragon id="estragon">戈戈</estragon>
<vladimir id="vladimir">狄狄</vladimir>
</noLeftTree>
<godot id="godot">戈多</godot>
<script> 'use strict' const godot = document.querySelector('#godot') const noLeftTree = document.querySelector('#noLeftTree') const ioCallback = entries => { console.log(entries[0].intersectionRatio <= 0 ? '戈多沒來,咱們先各自幹各自的活吧' : '戈多快到了,走,咱們集合去') } const ioConfig = { threshold: [0, 0.25, 0.5, 0.75, 1] } const io = new IntersectionObserver(ioCallback, ioConfig) io.observe(godot) </script>
複製代碼
其實若是肯花時間去研究,利用好上述三個API,是能夠實現不少頗有趣的效果的,上面的只是一個初嘗的DEMO,真正在項目裏是能夠實現不少很重要的功能。
不過戈戈 與 狄狄也等待戈多快70年了,就像癡情的女生等待遠走的渣男同樣,就是不來好歹也給個音信啊。
戈多心想:「我不過是迷路了麼,嚶嚶嚶」
若是你、喜歡探討技術,或者對本文有任何的意見或建議,你能夠掃描下方二維碼,關注微信公衆號「 魚頭的Web海洋 」,隨時與魚頭互動。歡迎!衷心但願能夠碰見你。