<返回更多

让你监听页面所有点击事件,你会怎么做?

2023-08-28  微信公众号  前端之神
加入收藏

前言

大家好,我是林三心,用最通俗易懂的话讲最难的知识点是我的座右铭,基础是进阶的前提是我的初心~

背景

如果在做某个平台的时候,我们需要统计用户点击的次数,点击的区域,点击元素,等等,那我们应该怎么去做比较合适呢?

举个例子,我想在用户点击页面上的每一个元素时,我都能把这个元素的DOM节点信息记录下来,并且上报到服务器,便于后面产品那边的统计用户喜好~

公共函数?处处调用?

那我们要怎么去做呢?写一个公共函数吗?然后去统一做上报吗?

我首先写一个函数,这是一个获取点击元素信息的函数,我们可以在点击的 event 参数中拿到目标元素 target

图片图片

const reportDOM = (e: PointerEvent) => {
  // 获取到点击的目标元素
  const el = e.target
  // 把目标元素解析成字符串
  const detAIl = htmlElementAsString(el)
  // 进行上报
  report(detail)
}

// 上报函数
export const report = (detail) => {
  request(url, detail)
}
// 解析函数
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}>`;
}

写完这几个函数之后,我们只需要在每一个点击事件中去插入这个函数即可

const click1 = (e: PointerEvent) => {
  reportDOM(e)
  
  // coding....
}
const click2 = (e: PointerEvent) => {
  reportDOM(e)
  
  // coding....
}
const click3 = (e: PointerEvent) => {
  reportDOM(e)
  
  // coding....
}

但是一个页面中,点击事件非常多啊,不可能每一个事件中去插入这个函数,非常麻烦

全局监听 + elementFromPoint

基本做法

最好的办法就是把 click 事件挂载在 window 身上,然后根据 elementFromPoint 去计算坐标匹配的元素,进行解析上报

window.addEventListener(
  'click',
  (e: PointerEvent) => {
    // 通过坐标计算出目标元素
    const el = getTargetDomByPointerEvent(e);
    if (!el) return;
    // 把目标元素解析成字符串
    const detail = htmlElementAsString(el);
    // 进行上报
    report(detail);
  },
  true,
);

// 通过坐标计算目标元素
export const getTargetDomByPointerEvent = (e: PointerEvent) => {
  const el = document.elementFromPoint(e.pageX, e.pageY);
  if (el) {
    return el as HTMLElement;
  }

  return null;
};

拓展做法,只上报所需元素

我们可以通过配置一个数组 globalClickListeners ,只对我们所需要的 DOM 节点进行监听上报,

const globalClickListeners = [
  {
    selector: '.cla', // 选择器
  },
  {
    elementText: 'report2', // 元素文本
  },
  {
    selector: '.r', // 选择器 + 元素文本
    elementText: 'report3',
  },
];

那么我们需要对 window 的点击监听进行改造

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);
          // 点击元素是否包含所属选择器范围
          const isIncludes = [...(els as unknown as any[])].includes(el);
          // 包含则上报
          if (isIncludes) {
            const detail = htmlElementAsString(el);
            // 进行上报
            report(detail);
          }
        } else if (el.textContent === elementText) {
          // 文本相同情况
          const detail = htmlElementAsString(el);
          // 进行上报
          report(detail);
        }
      });
    }
  },
  true,
);

小结

其实上面就是埋点库中,全局点击上报的一种解决方案,看似小问题,但是其实面试了这么多人,感觉只有很少一部分人能回答的比较好~

结语

我是林三心

关键词:监听      点击(13)
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多监听相关>>>