前言

在事件代理中,往往有的时候我们需要生效的部分会存在其他元素影响,比如我可能需要响应一个卡片的点击事件,但是这个卡片里面自身又有其它link元素,比如卡片的分类,tag标签等,当我们点击分类或者tag标签,由于事件冒泡的原因,他也会触发事件代理的click事件,也就是父级元素的click事件。

但是显然我们不需要响应他们,如果单纯通过event.target去排查,是不够完善的,有可能这个target是一个无class的元素,或者是同时存在多个的元素,我们可能还希望通过指定他们的父级元素class来进行排除。

教程

const blackClassList = ["article-card-tag", "comments", "article-card-category"];
const wrap = document.querySelector(".article-card-wrap");


wrap.addEventListener("click", function(event) {
    const target = event.target;
    const parent = target.closest(".article-card");
    if (!parent) return;

    //如果点击的元素是黑名单className则不执行
    const isBlack = this.hasBlackClass(target, parent);
    if (isBlack) return;

    // 实际要响应的逻辑操作
});

function hasBlackClass(target, parent): boolean {
    // 当前target是否黑名单元素
    const isBlackTarget = Array.from(target.classList).find((className) => blackClassList.includes(className));
    if (isBlackTarget) return true;
    // 当前target的父级是否黑名单元素
    const blackDomList = blackClassList.flatMap((className) =>
        Array.from(parent.querySelectorAll(`.${className}`))
    );
    const isBlackChild = blackDomList.find((black) => black.contains(target));
    if (isBlackChild) return true;

    return false;
}

实现逻辑也很简单,首先我们要有一个范围,这个范围就是target点击的卡片容器,也就是parent元素,我们通过closest获取到。

然后我们先判断target元素本身是否就是黑名单中的元素,如果是,就返回true。

然后我们通过卡片来获取卡片里面的黑名单元素,通过新增的flatMap方法,将满足条件的元素打平成一个数组,然后查询数组中的元素是否包含target,如果包含,说明target是黑名单元素的child,我们返回true。

最后以上条件都不满足,返回false。

这种方式比通过递归获取target的父级,然后判断父级是否是黑名单元素性能更好,效率更高,唯一缺点就是每次事件都需要querySelectorAll查询一次黑名单元素,如果是点击相同卡片就会有一些浪费,解决办法就是加入缓存功能,但是由于我的博客主题不太有这种操作,所以就省略了。

分类: JavaScript 标签: javascript事件代理

评论

暂无评论数据

暂无评论数据

目录