新聞中心
前言
大家好,我是林三心,用最通俗易懂的話講最難的知識(shí)點(diǎn)是我的座右銘,基礎(chǔ)是進(jìn)階的前提是我的初心~

為玉溪等地區(qū)用戶提供了全套網(wǎng)頁設(shè)計(jì)制作服務(wù),及玉溪網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作、玉溪網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
背景
如果在做某個(gè)平臺(tái)的時(shí)候,我們需要統(tǒng)計(jì)用戶點(diǎn)擊的次數(shù),點(diǎn)擊的區(qū)域,點(diǎn)擊元素,等等,那我們應(yīng)該怎么去做比較合適呢?
舉個(gè)例子,我想在用戶點(diǎn)擊頁面上的每一個(gè)元素時(shí),我都能把這個(gè)元素的DOM節(jié)點(diǎn)信息記錄下來,并且上報(bào)到服務(wù)器,便于后面產(chǎn)品那邊的統(tǒng)計(jì)用戶喜好~
公共函數(shù)?處處調(diào)用?
那我們要怎么去做呢?寫一個(gè)公共函數(shù)嗎?然后去統(tǒng)一做上報(bào)嗎?
我首先寫一個(gè)函數(shù),這是一個(gè)獲取點(diǎn)擊元素信息的函數(shù),我們可以在點(diǎn)擊的 event 參數(shù)中拿到目標(biāo)元素 target
圖片
const reportDOM = (e: PointerEvent) => {
// 獲取到點(diǎn)擊的目標(biāo)元素
const el = e.target
// 把目標(biāo)元素解析成字符串
const detail = htmlElementAsString(el)
// 進(jìn)行上報(bào)
report(detail)
}
// 上報(bào)函數(shù)
export const report = (detail) => {
request(url, detail)
}
// 解析函數(shù)
export function htmlElementAsString(target: HTMLElement): string {
const tagName = target.tagName.toLowerCase();
if (tagName === 'body') {
return '';
}
let classNames = target.classList.value;
classNames = classNames !== '' ? ` class='${classNames}'` : '';
const id = target.id ? ` id="${target.id}"` : '';
const innerText = target.innerText;
return `<${tagName}${id}${classNames !== '' ? classNames : ''}>${innerText}${tagName}>`;
}寫完這幾個(gè)函數(shù)之后,我們只需要在每一個(gè)點(diǎn)擊事件中去插入這個(gè)函數(shù)即可
const click1 = (e: PointerEvent) => {
reportDOM(e)
// coding....
}
const click2 = (e: PointerEvent) => {
reportDOM(e)
// coding....
}
const click3 = (e: PointerEvent) => {
reportDOM(e)
// coding....
}但是一個(gè)頁面中,點(diǎn)擊事件非常多啊,不可能每一個(gè)事件中去插入這個(gè)函數(shù),非常麻煩
全局監(jiān)聽 + elementFromPoint
基本做法
最好的辦法就是把 click 事件掛載在 window 身上,然后根據(jù) elementFromPoint 去計(jì)算坐標(biāo)匹配的元素,進(jìn)行解析上報(bào)
window.addEventListener(
'click',
(e: PointerEvent) => {
// 通過坐標(biāo)計(jì)算出目標(biāo)元素
const el = getTargetDomByPointerEvent(e);
if (!el) return;
// 把目標(biāo)元素解析成字符串
const detail = htmlElementAsString(el);
// 進(jìn)行上報(bào)
report(detail);
},
true,
);
// 通過坐標(biāo)計(jì)算目標(biāo)元素
export const getTargetDomByPointerEvent = (e: PointerEvent) => {
const el = document.elementFromPoint(e.pageX, e.pageY);
if (el) {
return el as HTMLElement;
}
return null;
};拓展做法,只上報(bào)所需元素
我們可以通過配置一個(gè)數(shù)組 globalClickListeners ,只對(duì)我們所需要的 DOM 節(jié)點(diǎn)進(jìn)行監(jiān)聽上報(bào),
const globalClickListeners = [
{
selector: '.cla', // 選擇器
},
{
elementText: 'report2', // 元素文本
},
{
selector: '.r', // 選擇器 + 元素文本
elementText: 'report3',
},
];那么我們需要對(duì) window 的點(diǎn)擊監(jiān)聽進(jìn)行改造
window.addEventListener(
'click',
(e: PointerEvent) => {
const el = getTargetDomByPointerEvent(e);
if (!el) return;
if (globalClickListeners.length) {
globalClickListeners.forEach(({ selector, elementText, data = '' }) => {
if (selector) {
// 選擇器的情況
const els = document.querySelectorAll(selector);
// 點(diǎn)擊元素是否包含所屬選擇器范圍
const isIncludes = [...(els as unknown as any[])].includes(el);
// 包含則上報(bào)
if (isIncludes) {
const detail = htmlElementAsString(el);
// 進(jìn)行上報(bào)
report(detail);
}
} else if (el.textContent === elementText) {
// 文本相同情況
const detail = htmlElementAsString(el);
// 進(jìn)行上報(bào)
report(detail);
}
});
}
},
true,
);小結(jié)
其實(shí)上面就是埋點(diǎn)庫(kù)中,全局點(diǎn)擊上報(bào)的一種解決方案,看似小問題,但是其實(shí)面試了這么多人,感覺只有很少一部分人能回答的比較好~
結(jié)語
我是林三心
- 一個(gè)待過小型toG型外包公司、大型外包公司、小公司、潛力型創(chuàng)業(yè)公司、大公司的作死型前端選手;
- 一個(gè)偏前端的全干工程師;
- 一個(gè)不正經(jīng)的掘金作者;
- 逗比的B站up主;
- 不帥的小紅書博主;
- 喜歡打鐵的籃球菜鳥;
- 喜歡歷史的乏味少年;
- 喜歡rap的五音不全弱雞
分享名稱:讓你監(jiān)聽頁面所有點(diǎn)擊事件,你會(huì)怎么做?
地址分享:http://fisionsoft.com.cn/article/cdijeoc.html


咨詢
建站咨詢
