jQuery/JavaScript拖拽校验如何避免编写大量冗余多条件IF语句

问题描述
实现拖拽交互时需要满足两个终态规则:
- 元素全部拖拽到正确目标区域时,弹出胜利提示并禁用按钮
- 5个可拖拽选项全部放置错误时,同样禁用按钮,弹出"game over"提示
当前实现为每一种错误拖拽场景单独编写IF判断,希望找到更简便的校验方式,避免大量重复的IF判断。
原有实现代码:
function buttonDisabled(){ // TRUE if( $('#items-10').has('#item-1').length == 1 && $('#items-7').has('#item-2').length == 1 && $('#items-6').has('#item-3').length == 1 && $('#items-9').has('#item-4').length == 1 && $('#items-8').has('#item-5').length == 1 ) {$('#next').prop("disabled", false);} // False if( $('#items-10').has('#item-2').length == 1 && $('#items-7').has('#item-1').length == 1 && $('#items-6').has('#item-3').length == 1 && $('#items-9').has('#item-4').length == 1 && $('#items-8').has('#item-5').length == 1 ) { $('#next').prop("disabled", false);} if( $('#items-10').has('#item-3').length == 1 && $('#items-7').has('#item-2').length == 1 && $('#items-6').has('#item-1').length == 1 && $('#items-9').has('#item-4').length == 1 && $('#items-8').has('#item-5').length == 1 ) { $('#next').prop("disabled", false);} if( $('#items-10').has('#item-4').length == 1 && $('#items-7').has('#item-2').length == 1 && $('#items-6').has('#item-3').length == 1 && $('#items-9').has('#item-1').length == 1 && $('#items-8').has('#item-5').length == 1 ) { $('#next').prop("disabled", false);} if( $('#items-10').has('#item-5').length == 1 && $('#items-7').has('#item-2').length == 1 && $('#items-6').has('#item-3').length == 1 && $('#items-9').has('#item-4').length == 1 && $('#items-8').has('#item-1').length == 1 ) { $('#next').prop("disabled", false);} }
优化方案
你现在的写法有两个核心问题:一是试图枚举所有错误排列,5个拖拽项的错误排列总共有119种,根本不可能写完;二是把「是否完成所有拖拽」的状态判断和「拖拽结果是否正确」的逻辑混在了一起,甚至注释标了False的分支里,也写了启用按钮的逻辑,本身就有bug。
完全不需要枚举任何场景,按下面的逻辑实现即可:
- 把正确的拖拽匹配关系抽成独立配置,不要硬编码在判断语句里
- 每次拖拽动作结束后,先统计当前状态:多少项已经放到目标区、多少项放对、多少项放错
- 没放完全部项时,保持按钮禁用;放完全部项后,根据正确/错误的数量触发对应提示,统一禁用按钮
优化后的代码:
// 配置项:key为目标容器ID,value为该容器对应的正确拖拽项ID const CORRECT_MAP = { 'items-10': 'item-1', 'items-7': 'item-2', 'items-6': 'item-3', 'items-9': 'item-4', 'items-8': 'item-5' }; const TOTAL_COUNT = Object.keys(CORRECT_MAP).length; const $nextBtn = $('#next'); // 每次拖拽完成后调用这个校验函数即可 function checkDragStatus() { let placed = 0, correct = 0, wrong = 0; // 遍历所有目标容器,统计当前放置情况 for (const [containerId, rightItemId] of Object.entries(CORRECT_MAP)) { const $currentItem = $(`#${containerId}`).children('.drag-item'); // 给所有可拖拽项加drag-item公共类 if (!$currentItem.length) continue; placed++; $currentItem.attr('id') === rightItemId ? correct++ : wrong++; } // 未完成所有放置,不触发终态逻辑 if (placed !== TOTAL_COUNT) { $nextBtn.prop('disabled', true); return; } // 已全部放置完成,统一禁用按钮,判断结果 $nextBtn.prop('disabled', true); if (correct === TOTAL_COUNT) { alert('胜利!'); // 这里补充胜利后的业务逻辑 } else if (wrong === TOTAL_COUNT) { alert('game over'); // 这里补充失败后的业务逻辑 } else { // 部分正确部分错误的场景,按需求自行处理,比如提示错误允许调整 } }
这种写法的优势很明显:
- 没有任何重复判断,后续如果增减拖拽项、修改匹配规则,只需要改
CORRECT_MAP配置即可,不用动核心判断逻辑 - 不会遗漏任何错误场景,不管用户怎么拖拽放置,都能正确统计状态
- 逻辑分层清晰,不会出现原有代码里错误分支误启用按钮的问题
内容的提问来源于stack exchange,提问作者André
相关产品推荐
相关产品推荐

