jQuery图片Select组件问题:两个Select事件无法独立触发
修复jQuery多图片Select的事件分离问题
问题根源
- 全局数组未重置:
langArray定义在全局,遍历第二个.box时会继续累加第一个的选项,导致第二个下拉框内容重复 - 全局选择器操作:事件处理中使用
$(".btn-select")、$(".b")这类全局选择器,点击时会操作所有匹配元素,导致两个下拉框同时展开/内容同步 - 重复ID使用:HTML中两个
<ul>都用了id="a",ID在页面中必须唯一,会导致DOM选择混乱
修复方案
- 将
langArray移到.box的遍历循环内部,每次循环初始化空数组,确保每个下拉框的选项独立 - 事件处理时通过
$(this)定位当前操作的.box容器,只操作容器内的元素,避免影响其他下拉框 - 将重复的ID
a改为classa,保证DOM结构合法性
修复后的完整代码
HTML
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <div class="box" id="one"> <select class="vodiapicker"> <option>Select one</option> <option value="en" class="test" data-thumbnail="images/3.png"> English </option> <option value="au" data-thumbnail="images/3.png">Engllish (AU)</option> </select> <div class="lang-select"> <button class="btn-select" value=""></button> <div class="b"> <ul class="a"></ul> </div> </div> </div> <div class="box" id="two"> <select class="vodiapicker"> <option>Select one</option> <option value="en" class="test" data-thumbnail="images/3.png"> french </option> <option value="au" data-thumbnail="images/3.png">french F</option> </select> <div class="lang-select"> <button class="btn-select" value=""></button> <div class="b"> <ul class="a"></ul> </div> </div> </div>
CSS
.vodiapicker { display: none; } .a { padding-left: 0px; } .a img, .btn-select img { width: 18px; } .a li { list-style: none; padding-top: 5px; padding-bottom: 5px; } .a li:hover { background-color: #f4f3f3; } .a li img { margin: 5px; } .a li span, .btn-select li span { margin-left: 30px; } /* item list */ .b { display: none; width: 100%; max-width: 350px; box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); border: 1px solid rgba(0, 0, 0, 0.15); border-radius: 5px; } .open { display: block !important; } .btn-select { margin-top: 10px; width: 100%; max-width: 350px; height: 34px; border-radius: 5px; background-color: #fff; border: 1px solid #ccc; } .btn-select li { list-style: none; float: left; padding-bottom: 0px; } .btn-select:hover li { margin-left: 0px; } .btn-select:hover { background-color: #f4f3f3; border: 1px solid transparent; box-shadow: inset 0 0px 0px 1px #ccc; } .btn-select:focus { outline: none; } .lang-select { margin-left: 50px; }
JavaScript
$(".box").each(function () { // 每个box单独维护自己的选项数组 var langArray = []; var $box = $(this); $box.find(".vodiapicker option").each(function () { var img = $(this).attr("data-thumbnail"); var text = this.innerText; var value = $(this).val(); var item = '<li><img src="' + img + '" alt="" value="' + value + '"/><span>' + text + "</span></li>"; langArray.push(item); }); $box.find(".a").html(langArray); // 设置当前box的按钮初始值 $box.find(".btn-select").html(langArray[0]); $box.find(".btn-select").attr("value", "en"); // 检查本地存储,仅初始化当前box的语言 var sessionLang = localStorage.getItem("lang-" + $box.attr("id")); if (sessionLang) { // 找到对应value的选项 var targetItem = langArray.find(item => item.includes(`value="${sessionLang}"`)); if (targetItem) { $box.find(".btn-select").html(targetItem); $box.find(".btn-select").attr("value", sessionLang); } } }); // 事件委托绑定li点击事件,限定在.box范围内 $(document).on("click", ".box .a li", function () { var $li = $(this); var $box = $li.closest(".box"); var img = $li.find("img").attr("src"); var value = $li.find("img").attr("value"); var text = $li.find("span").text(); // 直接取span文本避免包含img内容 var item = '<li><img src="' + img + '" alt="" /><span>' + text + "</span></li>"; // 仅更新当前box的按钮 $box.find(".btn-select").html(item); $box.find(".btn-select").attr("value", value); $box.find(".b").toggle(); // 保存到本地存储,区分不同box localStorage.setItem("lang-" + $box.attr("id"), value); }); // 按钮点击仅切换当前box的下拉框 $(document).on("click", ".box .btn-select", function () { var $box = $(this).closest(".box"); // 关闭其他box的下拉框 $(".box").not($box).find(".b").hide(); // 切换当前box的下拉框 $box.find(".b").toggle(); });
额外优化说明
- 本地存储增加了box的ID作为前缀,避免两个下拉框的语言设置互相覆盖
- 点击按钮时自动关闭其他下拉框,提升交互体验
- 取文本时直接用
span的内容,避免包含img的空白字符
内容的提问来源于stack exchange,提问作者Anis Khoja
相关产品推荐
相关产品推荐

