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

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

前言

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

背景

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

举个例子,我想在用户点击页面上的每一个元素时,我都能把这个元素的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,
);

小结

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

结语

我是林三心

  • 一个待过小型toG型外包公司、大型外包公司、小公司、潜力型创业公司、大公司的作死型前端选手;
  • 一个偏前端的全干工程师;
  • 一个不正经的掘金作者;
  • 逗比的B站up主;
  • 不帅的小红书博主;
  • 喜欢打铁的篮球菜鸟;
  • 喜欢历史的乏味少年;
  • 喜欢rap的五音不全弱鸡
责任编辑:武晓燕 来源: 前端之神
相关推荐

2021-05-13 07:32:17

培训代码同事

2024-03-19 00:52:52

前端网页篡改

2021-01-14 05:23:32

高并发消息中间件

2011-07-03 21:13:04

SEO

2022-02-17 08:57:18

内存设计进程

2021-11-10 08:00:00

容器开发安全

2020-08-30 16:30:14

VMwarevSphere 6虚拟化

2021-07-09 10:11:34

Redis云数据技术

2021-07-22 06:25:14

敏捷开发用户体验CIO

2009-11-18 18:28:27

Oracle监听器

2019-06-17 09:49:27

裁员失业品牌

2011-09-30 13:37:35

51CTO博客一周热门薪酬

2012-06-20 15:01:25

iOS开发

2023-02-27 10:45:16

2011-10-25 16:06:16

服务器宕机数据中心

2021-04-26 07:53:06

DOM前端框架

2018-06-07 09:13:22

错误数据备份

2020-04-06 14:53:05

MySQL数据库字符串

2023-01-15 17:57:12

缓存技术kafka磁盘

2022-10-18 23:03:53

mysql架构slave
点赞
收藏

51CTO技术栈公众号