jscolor按钮绿色区域首次点击后失效问题求助
问题描述
点击按钮的绿色区域时,仅首次点击有效,后续所有点击均无响应(蓝色区域始终正常可用)。
使用JS代码实现选择颜色更新网站文本功能,但无法定位按钮点击失效原因。更换其他Font Awesome按钮问题依旧,这些按钮还用于其他链接和暗黑模式功能,怀疑是jscolor与Font Awesome的集成方式存在问题。
使用版本:
- jscolor/2.4.5
- font-awesome/5.15.4
部分HTML代码
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.4.5/jscolor.min.js"></script> <button class="theme-switch star-button"><i class="far fa-star"></i></button>
JS代码
document.addEventListener("DOMContentLoaded", function () { const starButtons = document.querySelectorAll('button.star-button'); // Initialize jscolor picker jscolor.presets.default = { width: 200, position: 'right', backgroundColor: '#333', insetColor: '#FFF', shadow: true, borderRadius: 6, borderWidth: 1, borderColor: '#444', previewElement: null }; function showColorPicker(e) { e.preventDefault(); e.stopPropagation(); const target = e.currentTarget.querySelector('i'); const picker = new jscolor(target, { onFineChange: 'updateColor(this)', valueElement: null, // This ensures that the color value is not applied to the button itself previewElement: null, // No preview element styleElement: null // No style element }); picker.show(); } if (starButtons.length > 0) { starButtons.forEach(button => { button.addEventListener('click', showColorPicker); button.addEventListener('touchstart', showColorPicker); // Add touchstart event listener for mobile const greenPart = button.querySelector('.green-part'); if (greenPart) { greenPart.addEventListener('click', handleGreenPartClick); greenPart.addEventListener('touchstart', handleGreenPartClick); // Add touchstart event listener for mobile } console.log('Star button event listener added'); }); } else { console.log('No star buttons found'); } function handleGreenPartClick(e) { e.preventDefault(); e.stopPropagation(); alert('Green part clicked!'); } // Apply the saved color on page load const savedColor = localStorage.getItem('selectedColor'); if (savedColor) { const hslColor = JSON.parse(savedColor); applyColor(hslColor); console.log('Applied saved color:', hslColor); } }); function updateColor(picker) { const hexColor = picker.toHEXString(); const hslColor = hexToHSL(hexColor); console.log('New color selected: ', hslColor); applyColor(hslColor); // Save the selected color to localStorage localStorage.setItem('selectedColor', JSON.stringify(hslColor)); } function applyColor(hslColor) { document.documentElement.style.setProperty('--clr-a-text', `hsl(${hslColor.h}, ${hslColor.s}%, var(--L-a-text))`); document.documentElement.style.setProperty('--clr-a-text-hvr', `hsl(${hslColor.h}, ${hslColor.s}%, calc(var(--L-a-text) * var(--L-a-text-hover-change)))`); } function hexToHSL(hex) { // Convert hex to RGB first let r = 0, g = 0, b = 0; if (hex.length === 7) { r = parseInt(hex.slice(1, 3), 16) / 255; g = parseInt(hex.slice(3, 5), 16) / 255; b = parseInt(hex.slice(5, 7), 16) / 255; } // Convert RGB to HSL let max = Math.max(r, g, b), min = Math.min(r, g, b); let h = 0, s = 0, l = (max + min) / 2; if (max !== min) { let d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; }
问题原因与修复方案
原因分析
每次点击按钮都会创建新的jscolor实例绑定到<i>元素上,首次点击后jscolor会修改该元素的DOM结构或添加内部事件监听,后续再创建实例时会触发冲突,导致绿色区域的点击事件被覆盖或失效。另外,e.preventDefault()的过度使用也会干扰事件正常传递。
修复方案
- 每个按钮仅初始化一次jscolor实例,避免重复创建引发的DOM冲突
- 调整事件监听逻辑,用事件冒泡阻止实现绿色区域与蓝色区域的功能隔离
- 移除不必要的
e.preventDefault(),避免干扰按钮默认行为
修改后的JS代码
document.addEventListener("DOMContentLoaded", function () { const starButtons = document.querySelectorAll('button.star-button'); // 初始化jscolor全局预设 jscolor.presets.default = { width: 200, position: 'right', backgroundColor: '#333', insetColor: '#FFF', shadow: true, borderRadius: 6, borderWidth: 1, borderColor: '#444', previewElement: null, hideOnLeave: true }; // 为每个按钮只初始化一次颜色选择器 starButtons.forEach(button => { const icon = button.querySelector('i'); const picker = new jscolor(icon, { onFineChange: 'updateColor(this)', valueElement: null, previewElement: null, styleElement: null }); picker.hide(); // 初始隐藏选择器 // 蓝色区域点击显示颜色选择器 function showColorPicker(e) { if (!e.target.closest('.green-part')) { picker.show(); } } button.addEventListener('click', showColorPicker); button.addEventListener('touchstart', showColorPicker); // 绿色区域点击逻辑 const greenPart = button.querySelector('.green-part'); if (greenPart) { function handleGreenPartClick(e) { e.stopPropagation(); // 阻止事件冒泡到按钮,避免触发颜色选择器 alert('Green part clicked!'); } greenPart.addEventListener('click', handleGreenPartClick); greenPart.addEventListener('touchstart', handleGreenPartClick); } console.log('Star button event listener added'); }); // 加载本地存储的颜色 const savedColor = localStorage.getItem('selectedColor'); if (savedColor) { const hslColor = JSON.parse(savedColor); applyColor(hslColor); console.log('Applied saved color:', hslColor); } }); // 以下函数保持不变 function updateColor(picker) { const hexColor = picker.toHEXString(); const hslColor = hexToHSL(hexColor); console.log('New color selected: ', hslColor); applyColor(hslColor); localStorage.setItem('selectedColor', JSON.stringify(hslColor)); } function applyColor(hslColor) { document.documentElement.style.setProperty('--clr-a-text', `hsl(${hslColor.h}, ${hslColor.s}%, var(--L-a-text))`); document.documentElement.style.setProperty('--clr-a-text-hvr', `hsl(${hslColor.h}, ${hslColor.s}%, calc(var(--L-a-text) * var(--L-a-text-hover-change)))`); } function hexToHSL(hex) { let r = 0, g = 0, b = 0; if (hex.length === 7) { r = parseInt(hex.slice(1, 3), 16) / 255; g = parseInt(hex.slice(3, 5), 16) / 255; b = parseInt(hex.slice(5, 7), 16) / 255; } let max = Math.max(r, g, b), min = Math.min(r, g, b); let h = 0, s = 0, l = (max + min) / 2; if (max !== min) { let d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; }
关键修改点
- 每个按钮仅初始化一次jscolor实例,避免重复创建导致的DOM结构冲突
- 绿色区域点击时通过
e.stopPropagation()阻止事件冒泡,实现功能隔离 - 移除
e.preventDefault(),恢复按钮默认行为 - 调整颜色选择器触发逻辑,仅在点击非绿色区域时显示
内容的提问来源于stack exchange,提问作者doodlebob
相关产品推荐
相关产品推荐

