W3Schools自定义select下拉框通过JS动态插入后无法展开问题
问题原因
你所用的自定义下拉组件的初始化逻辑仅会在页面初次加载时执行一次,只会遍历处理此时DOM中已存在的.custom-select元素,自动生成额外的自定义结构、绑定交互事件。你后续通过JavaScript动态插入的DOM元素不会被初始逻辑自动识别,因此缺少可交互的自定义结构,导致点击无法展开。
解决方案
步骤1:抽离可复用的初始化函数
将原组件内置的初始化逻辑抽离为可重复调用的公共函数,同时增加已初始化标记避免重复处理元素:
// 自定义下拉初始化函数,可传入目标元素仅初始化该范围内的下拉 function initCustomSelect(targetEl = document) { let selectWrappers = targetEl.getElementsByClassName("custom-select"); for (let i = 0; i < selectWrappers.length; i++) { const selectEl = selectWrappers[i].getElementsByTagName("select")[0]; // 已初始化的元素跳过处理 if (selectEl.dataset.initialized) continue; selectEl.dataset.initialized = 'true'; // 生成选中项展示容器 const selectedEl = document.createElement("div"); selectedEl.className = "select-selected"; selectedEl.textContent = selectEl.options[selectEl.selectedIndex].textContent; selectWrappers[i].appendChild(selectedEl); // 生成下拉选项容器 const optionsContainer = document.createElement("div"); optionsContainer.className = "select-items select-hide"; // 遍历option生成自定义选项 for (let j = 0; j < selectEl.options.length; j++) { const optionItem = document.createElement("div"); optionItem.textContent = selectEl.options[j].textContent; optionItem.addEventListener("click", function() { // 同步原select的选中值 selectEl.selectedIndex = j; selectedEl.textContent = this.textContent; // 移除同组选中标记 const sameSelected = optionsContainer.getElementsByClassName("same-as-selected"); for (let k = 0; k < sameSelected.length; k++) { sameSelected[k].classList.remove("same-as-selected"); } this.classList.add("same-as-selected"); // 关闭下拉 selectedEl.click(); }); optionsContainer.appendChild(optionItem); } selectWrappers[i].appendChild(optionsContainer); // 绑定选中容器点击切换下拉事件 selectedEl.addEventListener("click", function(e) { e.stopPropagation(); closeAllSelect(this); optionsContainer.classList.toggle("select-hide"); this.classList.toggle("select-arrow-active"); }); } } // 全局关闭所有下拉函数 function closeAllSelect(activeEl = null) { const allSelected = document.getElementsByClassName("select-selected"); const allOptions = document.getElementsByClassName("select-items"); for (let i = 0; i < allSelected.length; i++) { if (activeEl !== allSelected[i]) { allSelected[i].classList.remove("select-arrow-active"); } } for (let i = 0; i < allOptions.length; i++) { if (activeEl?.nextSibling !== allOptions[i]) { allOptions[i].classList.add("select-hide"); } } } // 全局点击关闭下拉 document.addEventListener("click", () => closeAllSelect()); // 页面加载完成后初始化所有静态下拉 document.addEventListener("DOMContentLoaded", () => initCustomSelect());
步骤2:动态插入DOM后调用初始化函数
修改你的addRow方法,插入新节点后立即对新插入的下拉组件执行初始化:
function addRow(btn) { const contentContainer = document.querySelector("#content"); contentContainer.insertAdjacentHTML( "afterbegin", `<tr> <td>${btn.id}</td> <td> <div class="custom-select"> <select> <option value="0">IS</option> <option value="1">IS 1</option> <option value="2">IS 2</option> </select> </div> </td> </tr>` ); // 仅初始化刚插入的新行内的下拉,避免重复处理已有元素 const newInsertedRow = contentContainer.querySelector("tr:first-child"); initCustomSelect(newInsertedRow); }
注意事项
如果需要提交表单获取选中值,建议为每个动态生成的select元素设置唯一的name或id属性,避免取值冲突。
内容的提问来源于stack exchange,提问作者magic bean
相关产品推荐
相关产品推荐

