如何实现动态金字塔中区块按1-9、a-z规则排序显示?
嘿,我看到你在动态金字塔的区块排序上碰到了麻烦,这事儿其实是JavaScript默认的排序逻辑在搞鬼,咱们一步步解决它:
问题根源
你用的values.sort()是按字符串的Unicode码点来排序的,比如"6g"里的"6" Unicode值是54,比"4p"里的"4"(52)大,所以默认排序会把"6g"放在"4p"前面,这完全不符合你想要的「先按1-9数字排序,数字相同再按a-z字母排序」的规则。另外,你之前只排序了数组,但没同步更新页面上的DOM元素顺序,所以页面显示还是添加区块的原始顺序。
解决方案
咱们要做两件核心的事:自定义排序规则,然后让DOM和排序后的数组保持同步。
1. 写一个符合需求的排序函数
把你代码里的values.sort()替换成下面这个自定义比较函数,它会先比较数字部分,数字相同再比字母:
function compareBlocks(a, b) { // 提取每个名称的数字部分,转成数字类型 const numA = parseInt(a.name.charAt(0), 10); const numB = parseInt(b.name.charAt(0), 10); // 数字不同时,小的在前 if (numA !== numB) { return numA - numB; } // 数字相同时,按字母顺序排序(用localeCompare能保证正确的字母排序) return a.name.slice(1).localeCompare(b.name.slice(1)); } // 用自定义函数排序数组 values.sort(compareBlocks);
2. 让页面显示和数组同步
光排序数组没用,页面上的区块还是原来的顺序,所以咱们需要一个渲染函数,每次添加/删除区块后,根据排序后的数组重新生成页面上的金字塔:
首先,添加这个渲染函数:
function renderPyramid() { // 先清空现有的金字塔列表 $('.pyramid').empty(); // 遍历排序后的数组,逐个创建区块 values.forEach(blockInfo => { // 把区块的所有信息(名称、颜色、宽度、输入值)整合渲染 const $block = $(`<li><div class="item" style="width:${blockInfo.width}px; border-bottom: 60px solid ${blockInfo.color} ;"><input class="values" type="text" placeholder="${blockInfo.name}" maxlength="2" value="${blockInfo.value}"></div></li>`); // 保存用户修改的输入值,避免渲染后丢失 $block.find('.values').on('input', function() { blockInfo.value = $(this).val(); }); $('.pyramid').append($block); }); }
3. 修改添加和删除逻辑
原来的代码是直接append区块,现在要改成存储区块的完整信息,然后排序后调用渲染函数:
- 添加区块的修改:把原来的字符串存储改成对象存储,包含所有需要的信息,再排序渲染:
// 把区块的所有信息存在对象里,方便后续渲染 const newBlock = { name: number + resultLetter, color: resultColor, width: plus, value: "" // 用来存用户输入的内容 }; values.push(newBlock); values.sort(compareBlocks); renderPyramid(); // 调用渲染函数更新页面 console.log(values);
- 删除区块的修改:直接删除数组最后一项后调用渲染函数,不用再手动操作DOM:
$('#remove-block .button').click(function() { if (values.length === 0) return; // 防止数组为空时报错 values.pop(); // 直接删除最后一项,比splice更简洁 renderPyramid(); console.log(values); })
完整的修改后JS代码
$(document).ready(function() { //Add Block Functionality let values = []; // 自定义区块排序函数 function compareBlocks(a, b) { const numA = parseInt(a.name.charAt(0), 10); const numB = parseInt(b.name.charAt(0), 10); if (numA !== numB) { return numA - numB; } return a.name.slice(1).localeCompare(b.name.slice(1)); } // 渲染金字塔的函数 function renderPyramid() { $('.pyramid').empty(); values.forEach(blockInfo => { const $block = $(`<li><div class="item" style="width:${blockInfo.width}px; border-bottom: 60px solid ${blockInfo.color} ;"><input class="values" type="text" placeholder="${blockInfo.name}" maxlength="2" value="${blockInfo.value}"></div></li>`); $block.find('.values').on('input', function() { blockInfo.value = $(this).val(); }); $('.pyramid').append($block); }); } $('#add-block .button').click(function() { var lastwidth = $('.pyramid li:last-child .item').width(); var plus = lastwidth == null ? 90 : lastwidth + 190; var number = Math.floor(Math.random() * 9) + 1; function randLetter() { var letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]; return letters[Math.floor(Math.random() * letters.length)]; } var resultLetter = randLetter(); function randColor() { var colors = ["green", "yellowgreen", "Chocolate", "goldenrod", "cadetblue", "firebrick", "magenta", "LightSeaGreen", "Peru", "Sienna", "SlateBlue", "Snow", "Tan", "Skyblue"]; return colors[Math.floor(Math.random() * colors.length)]; } var resultColor = randColor(); const newBlock = { name: number + resultLetter, color: resultColor, width: plus, value: "" }; values.push(newBlock); values.sort(compareBlocks); renderPyramid(); console.log(values); }); //Remove Block Functionality $('#remove-block .button').click(function() { if (values.length === 0) return; values.pop(); renderPyramid(); console.log(values); }) });
这样修改后,每次添加区块都会自动按「数字1-9优先,同数字下字母a-z」的规则排列,而且还能保留每个区块的颜色和用户输入的内容,不会每次渲染都重置啦!
内容的提问来源于stack exchange,提问作者Rummel17
相关产品推荐
相关产品推荐

