js如何實現(xiàn)元素曝光上報
進行數(shù)據(jù)上報的時候,經(jīng)常會遇到列表數(shù)據(jù)曝光上報的問題,只對在當前可視范圍內(nèi)的數(shù)據(jù)內(nèi)容進行曝光上報,而對于未在可視范圍內(nèi)的數(shù)據(jù)不進行曝光上報,等待用戶滾動頁面或者區(qū)域使元素出現(xiàn)在可視范圍內(nèi)時才進行曝光上報。
解決方案
目前針對此類問題,主要有兩種解決方案。
方案一:監(jiān)聽頁面或者區(qū)域scroll事件,通過getBoundingClientRect接口取元素的位置與可視窗口進行判斷。
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
var width_st = rect.width / 2,
height_st = rect.height / 2;
var innerHeight = window.innerHeight,
innerWidth = window.innerWidth;
if ( rect.top <=0 && rect.height > innerHeight
|| rect.left <= 0 && rect.width > innerWidth
) {
return rect.left * rect.right <= 0
|| rect.top * rect.bottom <= 0
}
return (
rect.height > 0
&& rect.width > 0
&& ( ( rect.top >= 0 && rect.top <= innerHeight - height_st )
|| ( rect.bottom >= height_st && rect.bottom <= innerHeight ) )
&& ( ( rect.left >= 0 && rect.left <= innerWidth - width_st )
|| ( rect.right >= width_st && rect.right <= innerWidth ) )
);
}
var nodes = document.querySelectorAll(".item")
function report(node) {
// 上報的邏輯
}
window.onscroll = function() {
nodes.forEach(node => {
if( isElementInViewport(node) ) {
report(node)
}
})
}
優(yōu)點:兼容性好
缺點:
- 需要關(guān)注頁面或者區(qū)域的scroll事件
- 頻繁的scroll事件,性能問題
方案二:通過 IntersectionObserver 監(jiān)聽元素是否處于可視范圍
function report(node) {
// 上報的邏輯
}
var intersectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if( entry.intersectionRatio > 0 ) {
report(entry.target)
}
})
})
var nodes = document.querySelectorAll(".item")
nodes.forEach(node => {
intersectionObserver.observe(node)
})
優(yōu)點:
- 無須關(guān)注 scroll
- 回調(diào)是異步觸發(fā),不會頻繁觸發(fā),性能好
缺點:兼容性不好?
實際上,針對兼容性問題,w3c 官方提供了對應(yīng) polyfill, 因此intersectionObserver用于生產(chǎn)是可行的。
總結(jié)
筆者在實際運用中,通過 IntersectionObserver 封裝了一個簡單的調(diào)用庫,應(yīng)用于可視化埋點 sdk 中,用于解決元素曝光問題,如下
require('intersection-observer'); // polyfill
class Exposure {
constructor(callback) {
if (!callback || typeof callback !== 'function') {
throw new Error("need callback or selector param")
return
}
this.intersectionObserver = new IntersectionObserver((entries) => {
entries.forEach(item => {
if (item.intersectionRatio > 0) {
if (item.target) {
callback(item.target, item)
this.intersectionObserver.unobserve(item.target)
}
}
})
});
}
observe(selector, ignoreExposured) {
if (!this.intersectionObserver || !selector) {
return
}
let nodes = []
if( this.isDOM(selector) ) { // dom節(jié)點
nodes = [selector]
}else { // 選擇器
nodes = document.querySelectorAll(selector)
}
if (!nodes.length) {
return
}
nodes.forEach(node => {
if (!ignoreExposured && node.__wg__tracker__exposured__) {
return
}
node.__wg__tracker__exposured__ = true
// 開始觀察
this.intersectionObserver.observe(
node
);
})
}
disconnect() {
if (!this.intersectionObserver) {
return
}
this.intersectionObserver.disconnect()
}
isDOM(obj) {
if( !obj ) {
return false
}
if( typeof HTMLElement === 'object' ) {
return obj instanceof HTMLElement
}
if( typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string' ) {
return true
}
return false
}
}
export default Exposure
調(diào)用方法:
function report() {}
var exposurer = new Exposure((node) => {
report(node)
})
exposurer.observe(".item)
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
javascript 構(gòu)建模塊化開發(fā)過程解析
這篇文章主要介紹了javascript 構(gòu)建模塊化開發(fā)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-09-09
JavaScript使用AOP編程思想實現(xiàn)監(jiān)聽HTTP請求
這篇文章主要為大家詳細介紹了如何在JavaScript使用AOP編程思想實現(xiàn)監(jiān)聽HTTP請求,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下2024-02-02
javascript之通用簡單的table選項卡實現(xiàn)(二)
上篇中的選項卡存在這樣的問題:把邏輯封裝在table.js中,不夠靈活,也就是說如果某個選項卡是實現(xiàn)異步請求或者跳轉(zhuǎn),而非div的顯隱切換,那么就得修過table.js來達到目的,顯然不是我所需要的。2010-05-05
基于bootstrap的文件上傳控件bootstrap fileinput
這篇文章主要為大家詳細介紹了基于bootstrap的文件上傳控件bootstrap fileinput,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12

