ES5实现配色选择时的事件冒泡与父元素获取问题
解决配色选择器点击子元素不触发切换的问题
我明白你碰到的麻烦了:点击单选按钮、标签或者颜色块时没法切换配色,只有点击.scheme-color__option的空白区域才生效。这是因为你当前的代码只在event.target恰好是.scheme-color__option元素时才执行逻辑,但实际点击子元素时,target指向的是这些子节点,条件不满足自然就没反应。下面给你一步步解决的方案:
核心问题分析
你的事件委托绑定在.scheme-color__list上,这个思路本身没问题,但判断条件e.target.className === "scheme-color__option"太严苛——只有点击这个div本身的时候才会触发逻辑,而点击它内部的input、label或者td时,target是这些子元素,根本不会进入逻辑分支。
解决方案步骤
1. 实现ES5兼容的元素向上查找方法
因为ES5没有原生的Element.closest()方法,我们可以自己写一个函数,从触发事件的元素开始,向上查找最近的指定类名的父元素:
function findParentByClass(element, className) { while (element && element.nodeType === 1) { if (element.classList.contains(className)) { return element; } element = element.parentNode; } return null; }
2. 修改事件处理逻辑
在点击事件里,用上面的函数找到真正的.scheme-color__option元素,而不是直接判断target:
schemeColorList.addEventListener('click', function(e) { // 找到当前点击元素所属的scheme-color__option var targetOption = findParentByClass(e.target, 'scheme-color__option'); // 如果没找到匹配元素,直接返回 if (!targetOption) return; // 移除所有选项的选中状态 for (var j = 0; j < schemeColorOptions.length; j++) { var optionItem = schemeColorOptions[j]; // 注意:div没有checked属性,要操作内部的input optionItem.querySelector('input').checked = false; optionItem.classList.remove('is-selected'); } // 设置当前选项为选中状态 targetOption.classList.add('is-selected'); targetOption.querySelector('input').checked = true; // 获取当前选中的配色值 var colorCells = targetOption.querySelectorAll('.scheme-color__palette td'); var pColor = colorCells[0].style.backgroundColor; var sColor = colorCells[1].style.backgroundColor; var tColor = colorCells[2].style.backgroundColor; // 更新页面样式表 var styleSheets = document.styleSheets; for (var i = 0; i < styleSheets.length; i++) { var rules = styleSheets[i].cssRules || styleSheets[i].rules; if (!rules) continue; // 跳过无权限访问的跨域样式表 for (var j = 0; j < rules.length; j++) { switch(rules[j].selectorText) { case ".site-header": rules[j].style.backgroundColor = pColor; break; case ".site-nav": rules[j].style.backgroundColor = sColor; rules[j].style.borderColor = tColor; break; case ".site-nav__link:hover": rules[j].style.backgroundColor = pColor; break; } } } // 阻止事件冒泡(可选,若上层有其他点击事件冲突可启用) e.stopPropagation(); });
3. 修复原代码的小问题
- 原代码里
optionItem.checked = false是错误的,optionItem是div元素,没有checked属性,应该操作内部的input标签。 - 获取颜色的循环可以简化,直接按索引取值即可,无需遍历所有颜色再赋值。
- 遍历样式表时,加上
if (!rules) continue可以避免跨域样式表的权限报错。
完整修改后的JS代码
// 自定义ES5兼容的父元素查找函数 function findParentByClass(element, className) { while (element && element.nodeType === 1) { if (element.classList.contains(className)) { return element; } element = element.parentNode; } return null; } var schemeColorList = document.querySelector('.scheme-color__list'); var schemeColorOptions = document.querySelectorAll('.scheme-color__option'); schemeColorList.addEventListener('click', function(e) { var targetOption = findParentByClass(e.target, 'scheme-color__option'); if (!targetOption) return; // 重置所有选项状态 for (var j = 0; j < schemeColorOptions.length; j++) { var option = schemeColorOptions[j]; option.querySelector('input').checked = false; option.classList.remove('is-selected'); } // 激活当前选中的选项 targetOption.classList.add('is-selected'); targetOption.querySelector('input').checked = true; // 获取配色值 var colorCells = targetOption.querySelectorAll('.scheme-color__palette td'); var pColor = colorCells[0].style.backgroundColor; var sColor = colorCells[1].style.backgroundColor; var tColor = colorCells[2].style.backgroundColor; // 更新页面样式 var styleSheets = document.styleSheets; for (var i = 0; i < styleSheets.length; i++) { var rules = styleSheets[i].cssRules || styleSheets[i].rules; if (!rules) continue; for (var j = 0; j < rules.length; j++) { switch(rules[j].selectorText) { case ".site-header": rules[j].style.backgroundColor = pColor; break; case ".site-nav": rules[j].style.backgroundColor = sColor; rules[j].style.borderColor = tColor; break; case ".site-nav__link:hover": rules[j].style.backgroundColor = pColor; break; } } } e.stopPropagation(); });
这样修改后,不管你点击.scheme-color__option内部的任何元素(单选框、标签、颜色块),都会触发配色切换,同时也处理了事件冒泡的问题。
内容的提问来源于stack exchange,提问作者Aurelian Spodarec
相关产品推荐
相关产品推荐

