jQuery多选下拉框选项移动后可见选项计数异常问题
问题分析与解决方案
我来帮你拆解一下遇到的两个核心问题:
1. 计数异常的原因
你在remTerm函数里的计数逻辑是在执行移除操作之前统计可见选项数量的,所以当你选中两个选项点击移除时,console.log输出的是移除前的可见数量(也就是3),这其实是代码执行顺序导致的——你先数了数有多少可见选项,才开始移除操作。
如果是移除后再次点击移除按钮,计数依然显示3,那问题出在jQuery 1.8.0对<option>元素的:hidden判断上。旧版本jQuery对<option>的display:none识别有兼容性问题,有些浏览器里设置hide()后,is(':hidden')依然会返回false,导致计数错误。
2. option:selected包含隐藏选项的原因
不管选项是否可见,只要它带有selected属性,:selected选择器就会匹配到它。你在移除时只隐藏了选中的选项,但没有清除它们的selected属性,所以这些隐藏选项依然会被算作“选中”状态,后续操作会被重复处理。
修复方案
方案一:改用“移动选项”的实现思路(更可靠)
抛弃show/hide的方式,直接把选项从一个下拉框移动到另一个,这样DOM结构清晰,不会有隐藏选项和选中状态残留的问题。修改后的代码如下:
JavaScript 代码
jQuery("#term_add").click(function() { addTerm(); }); jQuery("#term_rem").click(function() { remTerm(); }); function addTerm() { var selectedOpts = jQuery("#all_terms option:selected"); if (selectedOpts.length === 0) { alert('Please select at least one term from the Terms drop-down to add'); return; } // 把选中的选项移动到目标下拉框 selectedOpts.appendTo("#terms"); // 清除源下拉框的选中状态 jQuery("#all_terms option:selected").removeAttr("selected"); // 这里可以触发你的级联逻辑 } function remTerm() { var selectedOpts = jQuery("#terms option:selected"); if (selectedOpts.length === 0) { alert('Please select at least one term from the Selected Terms drop-down to remove'); return; } // 把选中的选项移回源下拉框 selectedOpts.appendTo("#all_terms"); // 清除目标下拉框的选中状态 jQuery("#terms option:selected").removeAttr("selected"); // 检查选中框是否为空,执行对应的级联逻辑 var visibleCount = jQuery("#terms option").length; console.log('Visible options in Selected Terms: ' + visibleCount); if (visibleCount === 0) { // Do something when empty } else { // Do something when not empty } }
HTML 代码(简化版本)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script> <table class="formTable" cellspacing="0" cellpadding="0"> <tr> <td><h5>Available Terms</h5></td> <td> <div id="terms_div"> <select multiple="" id="all_terms" name="all_terms" style="width:100px;"> <option value="Fall 2014" title="Fall 2014">Fall 2014</option> <option value="Fall 2015" title="Fall 2015">Fall 2015</option> <option value="Fall 2018" title="Fall 2018">Fall 2018</option> <option value="SPRING 2015" title="SPRING 2015">SPRING 2015</option> <option value="SPRING 2016" title="SPRING 2016">SPRING 2016</option> <option value="SUMMER 2016" title="SUMMER 2016">SUMMER 2016</option> <option value="Spring 2017" title="Spring 2017">Spring 2017</option> </select> </div> </td> </tr> <tr> <td class="title" style="vertical-align:middle;padding:20px;"> <input class="btn_cn" title="Add terms to the report" type="button" id="term_add" name="term_add" value="add >>"> <br><br> <input class="btn_cn" title="Remove terms from the report" type="button" id="term_rem" name="term_rem" value="<< remove"> </td> </tr> <tr> <td class="title width20" style="width:0em;"><h5>Selected Terms</h5></td> <td> <div id="selected_terms_div"> <select multiple="" class="filter menuItems" id="terms" name="terms" style="width:100px;"> <!-- 初始为空,选项通过JS移动过来 --> </select> </div> </td> </tr> </table>
方案二:修复原有show/hide逻辑(兼容旧实现)
如果必须保留原有思路,需要修正以下几点:
- 移除操作后清除隐藏选项的
selected属性; - 统计选中项时只匹配可见的选项;
- 改用
css('display') === 'none'判断选项是否隐藏(替代is(':hidden'),更可靠)。
修改后的remTerm函数:
function remTerm() { // 统计可见选项数量(用更可靠的判断方式) var count_all_the_visible_options_in_terms_dropdown = 0; jQuery("#terms option").each(function() { if(jQuery(this).css('display') !== 'none'){ count_all_the_visible_options_in_terms_dropdown++; } }); console.log( 'count_all_the_visible_options_in_terms_dropdown 1 => ' + count_all_the_visible_options_in_terms_dropdown); // 检查是否有可见的选中项(只统计可见的选中项) var selectedVisibleOpts = jQuery("#terms option:visible:selected"); if (selectedVisibleOpts.length === 0) { alert('Please select at least one term from the Selected Terms drop-down to remove'); return; } // 执行移除逻辑 selectedVisibleOpts.each(function() { var new_elem = jQuery(this).val(); jQuery('#all_terms option[value="' + new_elem + '"]').css('display', 'block'); // 隐藏并清除选中状态 jQuery(this).css('display', 'none').removeAttr('selected'); }); // 移除后重新统计数量,执行级联逻辑 var newCount = 0; jQuery("#terms option").each(function() { if(jQuery(this).css('display') !== 'none'){ newCount++; } }); if (newCount === 0) { // Do something when empty } else { // Do something when not empty } }
同时,addTerm函数也需要修正选中状态的清除:
function addTerm() { var selectedOpts = jQuery("#all_terms option:selected"); if (selectedOpts.length === 0) { alert('Please select at least one term from the Terms drop-down to add'); return; } selectedOpts.each(function() { var new_elem = jQuery(this).val(); jQuery('#terms option[value="' + new_elem + '"]').css('display', 'block'); // 隐藏并清除选中状态 jQuery(this).css('display', 'none').removeAttr('selected'); }); // 触发级联逻辑 // Do Something }
内容的提问来源于stack exchange,提问作者Ash_and_Perl
相关产品推荐
相关产品推荐

