自定义select组件onchange/onfocus事件无法触发问题求助
自定义Select组件事件绑定问题解决
问题描述
参照自定义select示例实现组件后,无法触发原<select>的onchange和onfocus事件,自定义选项也无法执行预期事件,需要为组件正确绑定事件。
解决方案
1. 手动触发原Select的change事件
原<select>被设置为display:none,无法通过原生交互触发change事件,需要在自定义选项的点击回调中,更新原select的选中状态后手动触发该事件:
c.addEventListener("click", function(e) { var y, i, k, s, h, sl, yl; s = this.parentNode.parentNode.getElementsByTagName("select")[0]; sl = s.length; h = this.parentNode.previousSibling; for (i = 0; i < sl; i++) { if (s.options[i].innerHTML == this.innerHTML) { s.selectedIndex = i; // 新增:触发原select的change事件 s.dispatchEvent(new Event('change')); h.innerHTML = this.innerHTML; y = this.parentNode.getElementsByClassName("same-as-selected"); yl = y.length; for (k = 0; k < yl; k++) { y[k].removeAttribute("class"); } this.setAttribute("class", "same-as-selected"); break; } } h.click(); });
2. 绑定focus与blur事件
给自定义的.select-selected元素添加tabindex使其可聚焦,再同步绑定focus和blur事件到原select:
// 在创建.select-selected元素后添加: a.setAttribute("tabindex", "0"); // 让div获得焦点能力 a.addEventListener("focus", function() { var s = this.parentNode.getElementsByTagName("select")[0]; s.dispatchEvent(new Event('focus')); // 聚焦时自动打开下拉框 closeAllSelect(this); this.nextSibling.classList.remove("select-hide"); this.classList.add("select-arrow-active"); }); a.addEventListener("blur", function() { // 延迟关闭,避免点击选项时直接触发blur导致下拉框提前关闭 setTimeout(() => { closeAllSelect(this); this.nextSibling.classList.add("select-hide"); this.classList.remove("select-arrow-active"); }, 150); });
3. 修复closeAllSelect函数逻辑bug
原函数中判断条件错误,会导致下拉框无法正确关闭,修正如下:
function closeAllSelect(elmnt) { var x, y, i, xl, yl, arrNo = []; x = document.getElementsByClassName("select-items"); y = document.getElementsByClassName("select-selected"); xl = x.length; yl = y.length; for (i = 0; i < yl; i++) { if (elmnt == y[i]) { arrNo.push(i); } else { y[i].classList.remove("select-arrow-active"); } } for (i = 0; i < xl; i++) { // 修正:只有当索引不在arrNo中时才隐藏 if (arrNo.indexOf(i) === -1) { x[i].classList.add("select-hide"); } } }
4. 正确绑定原Select的事件监听
确保在DOM加载完成后绑定原select的事件,避免元素未初始化导致绑定失败:
document.addEventListener('DOMContentLoaded', function() { let selectDiv = document.getElementById('selectopt'); selectDiv.addEventListener('change', function() { console.log('选中值变更:', this.value); }); selectDiv.addEventListener('focus', function() { console.log('select获得焦点'); }); });
修改后的完整JavaScript代码
var x, i, j, l, ll, selElmnt, a, b, c; x = document.getElementsByClassName("custom-select"); l = x.length; for (i = 0; i < l; i++) { selElmnt = x[i].getElementsByTagName("select")[0]; ll = selElmnt.length; a = document.createElement("DIV"); a.setAttribute("class", "select-selected"); a.setAttribute("tabindex", "0"); // 添加焦点能力 a.innerHTML = selElmnt.options[selElmnt.selectedIndex].innerHTML; // 绑定focus事件 a.addEventListener("focus", function() { var s = this.parentNode.getElementsByTagName("select")[0]; s.dispatchEvent(new Event('focus')); closeAllSelect(this); this.nextSibling.classList.remove("select-hide"); this.classList.add("select-arrow-active"); }); // 绑定blur事件 a.addEventListener("blur", function() { setTimeout(() => { closeAllSelect(this); this.nextSibling.classList.add("select-hide"); this.classList.remove("select-arrow-active"); }, 150); }); x[i].appendChild(a); b = document.createElement("DIV"); b.setAttribute("class", "select-items select-hide"); for (j = 1; j < ll; j++) { c = document.createElement("DIV"); c.innerHTML = selElmnt.options[j].innerHTML; c.addEventListener("click", function(e) { var y, i, k, s, h, sl, yl; s = this.parentNode.parentNode.getElementsByTagName("select")[0]; sl = s.length; h = this.parentNode.previousSibling; for (i = 0; i < sl; i++) { if (s.options[i].innerHTML == this.innerHTML) { s.selectedIndex = i; s.dispatchEvent(new Event('change')); // 触发change事件 h.innerHTML = this.innerHTML; y = this.parentNode.getElementsByClassName("same-as-selected"); yl = y.length; for (k = 0; k < yl; k++) { y[k].removeAttribute("class"); } this.setAttribute("class", "same-as-selected"); break; } } h.click(); }); b.appendChild(c); } x[i].appendChild(b); a.addEventListener("click", function(e) { e.stopPropagation(); closeAllSelect(this); this.nextSibling.classList.toggle("select-hide"); this.classList.toggle("select-arrow-active"); }); } function closeAllSelect(elmnt) { var x, y, i, xl, yl, arrNo = []; x = document.getElementsByClassName("select-items"); y = document.getElementsByClassName("select-selected"); xl = x.length; yl = y.length; for (i = 0; i < yl; i++) { if (elmnt == y[i]) { arrNo.push(i); } else { y[i].classList.remove("select-arrow-active"); } } for (i = 0; i < xl; i++) { if (arrNo.indexOf(i) === -1) { x[i].classList.add("select-hide"); } } } // 点击页面其他区域关闭下拉框 document.addEventListener("click", function() { closeAllSelect(); }); // 绑定原select的事件 document.addEventListener('DOMContentLoaded', function() { let selectDiv = document.getElementById('selectopt'); selectDiv.addEventListener('change', function() { console.log('选中值变更:', this.value); }); selectDiv.addEventListener('focus', function() { console.log('select获得焦点'); }); });
内容的提问来源于stack exchange,提问作者KrupaV
相关产品推荐
相关产品推荐

