如何在切换另一个Select2下拉框时清空当前下拉框?
我有两个多选Select2下拉框,要求每次只能选择其中一个。当前代码如下:
<div class="col-md-12"> <div class="form-group"> <label>Geo Blacklist</label> <select name="blacklist[]" multiple="multiple" id="blacklist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1" onchange="$('#whitelist').val([]).change();"> <option>a</option> <option>b</option> <option>c</option> </select> </div> </div> <div class="col-md-12"> <div class="form-group"> <label>Geo Whitelist</label> <select name="whitelist[]" multiple="multiple" id="whitelist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1" onchange="$('#blacklist').val([]).change();"> <option>x</option> <option>y</option> <option>z</option> </select> </div> </div>
选择任意下拉框时出现以下错误:
Uncaught RangeError: Maximum call stack size exceeded
at RegExp.exec ()
at [Symbol.replace] ()
at String.replace ()
at Function.camelCase (jquery.js:346:17)
at Function.style (jquery.js:6643:22)
at jquery.js:6866:12
at jQuery.access (jquery.js:4142:5)
at jQuery.fn.init.css (jquery.js:6849:10)
at Search.resizeSearch (select2.full.js:2032:18)
at DecoratedClass.resizeSearch (select2.full.js:580:32)
原因分析
当前代码的核心问题是无限递归触发change事件:选中blacklist时会清空whitelist并触发其change事件,而whitelist的change事件又会清空blacklist并触发它的change事件,循环往复直到浏览器调用栈溢出。
解决方法
方案1:使用Select2专属事件更新UI(避免触发全局change)
修改内联onchange代码,用trigger('change.select2')替代change(),这个事件只会更新Select2的UI,不会触发全局的change事件,从而避免循环:
<div class="col-md-12"> <div class="form-group"> <label>Geo Blacklist</label> <select name="blacklist[]" multiple="multiple" id="blacklist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1" onchange="$('#whitelist').val([]).trigger('change.select2');"> <option>a</option> <option>b</option> <option>c</option> </select> </div> </div> <div class="col-md-12"> <div class="form-group"> <label>Geo Whitelist</label> <select name="whitelist[]" multiple="multiple" id="whitelist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1" onchange="$('#blacklist').val([]).trigger('change.select2');"> <option>x</option> <option>y</option> <option>z</option> </select> </div> </div>
方案2:添加标志位防止递归(更灵活)
移除内联onchange属性,改用外部事件监听,通过一个标志位标记是否正在处理,避免循环触发:
HTML代码(移除内联事件)
<div class="col-md-12"> <div class="form-group"> <label>Geo Blacklist</label> <select name="blacklist[]" multiple="multiple" id="blacklist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1"> <option>a</option> <option>b</option> <option>c</option> </select> </div> </div> <div class="col-md-12"> <div class="form-group"> <label>Geo Whitelist</label> <select name="whitelist[]" multiple="multiple" id="whitelist" class="form-control select2" data-placeholder="Seleccionar uno o varios países" tabindex="1"> <option>x</option> <option>y</option> <option>z</option> </select> </div> </div>
JavaScript代码
let isUpdating = false; // 监听blacklist的change事件 $('#blacklist').on('change', function() { if (!isUpdating) { isUpdating = true; $('#whitelist').val([]).trigger('change.select2'); isUpdating = false; } }); // 监听whitelist的change事件 $('#whitelist').on('change', function() { if (!isUpdating) { isUpdating = true; $('#blacklist').val([]).trigger('change.select2'); isUpdating = false; } });
内容的提问来源于stack exchange,提问作者Luis Urán

