百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

JavaScript棘手代码(三)(js代码手册)

yund56 2025-07-23 21:41 12 浏览

问题:嵌套盒子的事件处理

我们有3个嵌套的盒子(box1、box2、box3)。当点击每个盒子时,将其ID记录到控制台。点击内部盒子时,不应该触发外部盒子的点击事件。

这个问题是关于什么?
这个问题是关于JavaScript中的事件处理和事件传播,特别是如何控制嵌套HTML元素的点击事件流。

核心问题是如何防止点击内部元素时也触发其父(外部)元素的点击事件。这是Web开发中的一个常见场景,你希望特定操作只在点击特定元素时发生,而不是其容器。

解决方案:有很多方法可以实现,但更优化的方式是将所有div包装在一个id为container父div中。

然后在父元素上添加事件监听器。


完整代码实现

HTML文件

<div id="container">
    <div id="box1" class="box">
      box1
      <div id="box2" class="box">
         box2
         <div id="box3" class="box">box3</div>
      </div>
    </div>
</div>

CSS文件

.box {
  min-width: 200px;
  width: fit-content; /* 匹配div内容宽度 */
  border: 1px solid #000;
  padding: 15px;
}

#box1 {
  background-color: yellow;
  padding: 10px;
}
#box2 {
  background-color: cyan;
  padding: 10px;
}
#box3 {
  background-color: red;
}

JavaScript文件

document.getElementById('container').addEventListener('click', event => {
  // 当点击容器元素或其任何子元素时执行
  if (event.target.classList.contains('box')) {
    /* 检查点击是否只发生在具有box类的元素上,因为我们不需要处理容器的其他子元素的点击,除了box。*/

    console.log('id is: ', event.target.id);
    event.stopPropagation(); // 防止事件在点击子元素时传播到父元素
  }
})

关键概念解释

1. 事件委托(Event Delegation)

o 在父元素上监听事件,而不是在每个子元素上

o 利用事件冒泡机制

o 减少事件监听器数量,提高性能

2. event.target

o 指向实际被点击的元素

o 不是事件监听器绑定的元素

o 用于确定具体是哪个子元素被点击

3. event.stopPropagation()

o 阻止事件继续冒泡到父元素

o 防止触发父元素的事件处理器

o 确保只有被点击的元素响应事件

4. classList.contains()

o 检查元素是否包含特定CSS类

o 用于过滤需要处理的元素

o 提供灵活的事件处理条件


性能优化考虑

重要提示:正如我之前所说,有很多方法可以解决这个问题,我们也可以为每个单独的div添加事件监听器,因为现在只有3个div,但如果数量更多,我们就需要循环等。

所以为了避免循环,我们选择了父元素。我们也可以选择<body>作为父元素,但那样脚本会搜索更大范围的代码,会耗时。因此我们将事件监听器的范围缩小到一个小的区域,即id为container的div


替代解决方案

方案1:为每个盒子单独添加事件监听器

document.getElementById('box1').addEventListener('click', (event) => {
  console.log('id is: box1');
  event.stopPropagation();
});

document.getElementById('box2').addEventListener('click', (event) => {
  console.log('id is: box2');
  event.stopPropagation();
});

document.getElementById('box3').addEventListener('click', (event) => {
  console.log('id is: box3');
  event.stopPropagation();
});

方案2:使用事件捕获

document.getElementById('container').addEventListener('click', event => {
  if (event.target.classList.contains('box')) {
    console.log('id is: ', event.target.id);
  }
}, true); // 第三个参数true启用捕获模式

方案3:使用事件委托的现代方法

document.getElementById('container').addEventListener('click', event => {
  const box = event.target.closest('.box');
  if (box) {
    console.log('id is: ', box.id);
    event.stopPropagation();
  }
});

实际应用场景

1. 导航菜单:处理嵌套菜单项的点击

2. 表单组件:处理复杂表单中的交互

3. 卡片布局:处理卡片内部的按钮点击

4. 模态框:处理模态框内容的交互

5. 拖拽组件:处理拖拽区域内的元素


最佳实践

1. 使用事件委托:减少事件监听器数量

2. 合理的作用域:选择合适的事件监听器绑定元素

3. 性能考虑:避免在大量元素上绑定事件

4. 代码可维护性:使用类名或数据属性进行过滤

5. 浏览器兼容性:考虑不同浏览器的事件处理差异


调试技巧

// 添加调试信息
document.getElementById('container').addEventListener('click', event => {
  console.log('Event target:', event.target);
  console.log('Current target:', event.currentTarget);
  console.log('Event phase:', event.eventPhase);
  
  if (event.target.classList.contains('box')) {
    console.log('Box clicked:', event.target.id);
    event.stopPropagation();
  }
});

更多JavaScript面试相关代码请访问:

o JavaScript棘手代码第二部分


关键概念总结

1. 事件委托:在父元素上监听子元素事件

2. 事件冒泡:事件从子元素向上传播到父元素

3. 事件捕获:事件从父元素向下传播到子元素

4. stopPropagation():阻止事件传播

5. target vs currentTarget:实际触发元素 vs 事件监听器绑定元素


扩展练习

练习1:动态添加元素的事件处理

// 动态添加新盒子
function addNewBox() {
  const container = document.getElementById('container');
  const newBox = document.createElement('div');
  newBox.className = 'box';
  newBox.id = 'box' + (document.querySelectorAll('.box').length + 1);
  newBox.textContent = newBox.id;
  container.appendChild(newBox);
}

// 事件委托自动处理新添加的元素
document.getElementById('container').addEventListener('click', event => {
  if (event.target.classList.contains('box')) {
    console.log('Clicked:', event.target.id);
  }
});

练习2:条件事件处理

document.getElementById('container').addEventListener('click', event => {
  if (event.target.classList.contains('box')) {
    const boxId = event.target.id;
    
    // 根据不同的盒子执行不同的操作
    switch(boxId) {
      case 'box1':
        console.log('外层盒子被点击');
        break;
      case 'box2':
        console.log('中层盒子被点击');
        break;
      case 'box3':
        console.log('内层盒子被点击');
        break;
    }
    
    event.stopPropagation();
  }
});

相关推荐

SM小分队Girls on Top,女神战队少了f(x)?

这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...

韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出

AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...

韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend

身高163的Giselle,长腿傲人,身材比例绝了...

假唱而被骂爆的女团:IVE、NewJeans、aespa上榜

在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...

新女团Aespa登时尚大片 四个少女四种style

来源:环球网

韩国女团aespa新歌MV曝光 画面梦幻造型超美

12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...

女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA

女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...

人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?

现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...

韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞

WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...

aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」

记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...

南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典

女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...

章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相

搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...

Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相

作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...

AESPA女团成员柳智敏karina大美女

真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...

对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了

哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...