冒泡排序可视化工具:点击Next按钮实现元素交换功能问题排查
冒泡排序可视化工具问题修复方案
原代码核心问题
- 重复绑定点击事件:页面加载时就执行双重循环绑定点击事件,但此时
newArray是空数组,循环不会执行;就算数组有值,也会给按钮绑定几十次点击事件,点击一次触发所有逻辑,完全混乱。 - 交换逻辑错误:使用
order属性交换时,赋值的是原数组的旧值,且DOM元素的类名未同步更新,后续对比会找错元素。 - 无步骤跟踪:没有记录当前执行到冒泡排序的哪一步,无法实现点击Next逐步执行的效果。
- 缺少高亮反馈:没有实现对比元素的高亮,用户无法直观看到当前操作的元素。
修正后的完整代码
HTML
<label>Enter numbers seperated by comma here</label> <input type="text" id="numbers_input"> <button type="button" id="create-btn">Create Array</button> <div class="num-holder"></div> <button id="sort-btn" class="sort-btn" type="button">Next</button> <script src="index.js"></script>
CSS
.num-holder { display: flex; justify-content: space-between; margin-top: 50px; margin-bottom: 10px; gap: 10px; } .num { background-color: rgba(227, 130, 130, 0.53); font-size: 30px; padding: 10px 20px; transition: background-color 0.3s; } /* 高亮当前对比的元素 */ .num.highlight { background-color: #ffd966; } /* 标记已排序完成的元素(可选) */ .num.sorted { background-color: #93c47d; } .as-console-wrapper { height: 40px }
JavaScript
let createBtn = document.getElementById('create-btn'); let sortBtn = document.getElementById('sort-btn'); let numHolder = document.querySelector('.num-holder'); let newArray = []; // 跟踪冒泡排序的当前步骤 let currentI = 0; let currentJ = 0; createBtn.addEventListener('click', () => { // 清空之前的数组和DOM元素 newArray = []; numHolder.innerHTML = ''; currentI = 0; currentJ = 0; // 解析输入为数字数组,过滤无效值 let data = document.getElementById('numbers_input').value; let newData = data.split(',').map(num => Number(num)).filter(num => !isNaN(num)); if (newData.length < 2) { alert('请输入至少两个有效数字'); return; } newArray = [...newData]; // 创建DOM元素 newArray.forEach((num, index) => { const div = document.createElement('div'); div.innerHTML = num; div.className = `num num-${index}`; div.setAttribute('data-val', num); numHolder.appendChild(div); }); }); sortBtn.addEventListener('click', () => { if (newArray.length === 0) { alert('请先创建数组'); return; } // 移除之前的高亮标记 document.querySelectorAll('.num.highlight').forEach(el => el.classList.remove('highlight')); // 冒泡排序终止条件:所有外层循环完成 if (currentI >= newArray.length - 1) { alert('排序完成'); return; } // 获取当前要对比的两个元素 let num1El = document.querySelector(`.num-${currentJ}`); let num2El = document.querySelector(`.num-${currentJ + 1}`); if (!num1El || !num2El) return; // 高亮当前对比元素 num1El.classList.add('highlight'); num2El.classList.add('highlight'); // 对比并交换 let num1 = parseInt(num1El.getAttribute('data-val')); let num2 = parseInt(num2El.getAttribute('data-val')); if (num1 > num2) { // 交换数组中的值 [newArray[currentJ], newArray[currentJ + 1]] = [newArray[currentJ + 1], newArray[currentJ]]; // 交换DOM元素的内容和data-val属性 [num1El.innerHTML, num2El.innerHTML] = [num2El.innerHTML, num1El.innerHTML]; [num1El.dataset.val, num2El.dataset.val] = [num2El.dataset.val, num1El.dataset.val]; } // 推进到下一个步骤 currentJ++; // 内层循环完成,推进外层循环,重置内层循环索引 if (currentJ >= newArray.length - currentI - 1) { currentI++; currentJ = 0; // 标记已排序完成的元素 document.querySelector(`.num-${newArray.length - currentI}`)?.classList.add('sorted'); } });
关键改动说明
- 步骤跟踪:用
currentI和currentJ两个变量记录当前冒泡排序执行到外层和内层循环的哪一步,每次点击Next只执行当前步骤的逻辑。 - 单次点击事件绑定:只给Sort按钮绑定一次点击事件,避免重复绑定导致的逻辑混乱。
- 正确的交换逻辑:同时交换数组中的值和DOM元素的内容、
data-val属性,确保数据和视图同步,不需要依赖order属性(直接交换内容更直观)。 - 高亮效果:添加
highlight类标记当前对比的元素,额外添加sorted类标记已完成排序的元素,提升可视化体验。 - 边界处理:添加数组为空、输入无效、排序完成的提示,避免报错。
内容的提问来源于stack exchange,提问作者Md Amir Sohail
相关产品推荐
相关产品推荐

