好,所以我对JS比较陌生,但是对python和java有很多经验。
我的代码有2个问题,需要帮助。首先,这是我的代码的解释和背景。
理想情况下,我需要最简单的结构化视觉排序程序,我可以将其用作基础,并逐步进行编码以供参考。我首先最大化了一个容器div,该容器用于填充x数量的divs.bars,在插入时,flexbox会自动处理div的宽度和位置。每个添加的div的高度是随机生成的,并存储在每个单独的元素属性中。我已经完成了所有事情,简单。然后,我制作了一个元素交换函数,该函数交换w DOM中的元素位置,效果很好。现在我的问题。我希望看到for循环迭代时实时排序的元素,但是直到循环结束才更新它们。我无法找到任何错误的“我的插入”算法也无法正常工作,但我认为我的工作方式不正确。任何帮助将不胜感激。寻找别人应该非常容易。
const sortDisplay = document.getElementById('sortDisplay');
let resetbtn = document.querySelector('.reset');
resetbtn.addEventListener('click', reset);
let count = 0;
let amount = 100;
// create div that has custom attribute value, unique style tag, default bar style and append.
function generateBar() {
// generate div
let bar = document.createElement('div');
// keep track of the total amount of bars
count++;
// assign random number 0-100 and setAttribute to the div
let temp = Math.floor(Math.random() * 101);
// create custom attribute that holds its value
bar.setAttribute('value', temp);
// create unique style tag with height as a percentage based on Attribute
let barHeight = document.createElement('style');
barHeight.innerHTML = `.barHeight${count} {height: ${temp}%;}`;
// add that unique style to the DOM
sortDisplay.appendChild(barHeight);
// now add that unique style to the div
bar.classList.add(`barHeight${count}`);
// use standard style from css as well
bar.classList.add('sortBar');
// now add that div to the DOM
sortDisplay.appendChild(bar);
}
// clear container div and regenerate
function reset() {
// clear all data within the container
sortDisplay.innerHTML = '';
// reset the count
count = 0;
// generate k bars
for (let i = 0; i < amount; i++) {
generateBar();
}
}
// when page is loaded reset
reset(amount);
// swap elements within the DOM
function swapElements(obj1, obj2) {
// create marker element and insert it above where obj1 is
var temp = document.createElement("div");
obj1.parentNode.insertBefore(temp, obj1);
// move obj1 to right before obj2
obj2.parentNode.insertBefore(obj1, obj2);
// move obj2 to right before where obj1 used to be
temp.parentNode.insertBefore(obj2, temp);
// remove temporary marker node
temp.parentNode.removeChild(temp);
}
// sort the divs within the DOM
function sort() {
for (let i = 1; i < amount; i++) {
let j = i;
for (j; j > 0; j--) {
if (document.querySelectorAll('.sortBar')[j].getAttribute('value') < document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
swapElements(document.querySelectorAll('.sortBar')[j], document.querySelectorAll('.sortBar')[j-1]);
}
else {
break;
}
}
}
}
// Button to run the sort function
button = document.querySelector('.button');
button.addEventListener('click', sort);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
width: 100%;
}
.sortDisplay {
background-color: #305c50;
background-image: linear-gradient(28deg, #305c50 0%, #6ab19e 70%, #82d8a6 100%);
display: flex;
align-items: flex-end;
justify-content: space-between;
height: 100%;
width: 100%;
overflow: hidden;
}
.btn-container {
position: absolute;
right: 0;
bottom: 0;
margin: 25px;
}
.btn-container button {
padding: 25px;
}
.sortBar {
flex: 1;
background-color: #0007;
}
<div class="btn-container">
<button class="reset">reset</button>
<button class="button">button</button>
</div>
<div id="sortDisplay"class="sortDisplay"></div>
该错误非常小:您正在比较字符串,而不是排序中的数字。添加数字转换:
if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
作为字符串,例如"3" > "29"
。
可视化不是“实时可见”的,因为代码的完成速度非常快,而且无需取消控制并等待DOM渲染。强制重新渲染DOM存在一些小问题,但我认为这在这里并不重要。
要解决此问题,请在循环中添加一个延迟,这非常简单,您只需要一个标准延迟函数(const delay = ms => new Promise(res => setTimeout(res, ms));
),在async
(sort
)前面的async function sort
,然后交换之间的适当延迟(await delay(DELAY_BETWEEN_SWAPS);
,当前为25毫秒。无法保证确切的时间,由于多种因素,可能需要一次22毫秒,以及下次27毫秒,但这并不是太重要)。
但是,这会导致取消问题:现在可以重置,而分类仍在进行(非同步性的难题)。因此,有必要检查当前的排序是否已取消。因此,每个分类过程都需要一个取消令牌,当按复位键时,可使用该令牌来停止旧的分类。最后但最不重要的一点是,开始新的排序(只需按“按钮”),也会自动取消最后的排序。
注意,我展示的是一些概念,但不一定是能赢得美容大奖的代码。我也没有更改任何“有效但我不会那样做”的内容-例如我更喜欢用画布而不是用大量的DOM更新制作动画。
工作版本:
const sortDisplay = document.getElementById('sortDisplay');
let resetbtn = document.querySelector('.reset');
resetbtn.addEventListener('click', reset);
const DELAY_BETWEEN_SWAPS = 25;
const delay = ms => new Promise(res => setTimeout(res, ms));
let cancelLast = () => {};
let count = 0;
let amount = 100;
// create div that has custom attribute value, unique style tag, default bar style and append.
function generateBar() {
// generate div
let bar = document.createElement('div');
// keep track of the total amount of bars
count++;
// assign random number 0-100 and setAttribute to the div
let temp = Math.floor(Math.random() * 101);
// create custom attribute that holds its value
bar.setAttribute('value', temp);
// create unique style tag with height as a percentage based on Attribute
let barHeight = document.createElement('style');
barHeight.innerHTML = `.barHeight${count} {height: ${temp}%;}`;
// add that unique style to the DOM
sortDisplay.appendChild(barHeight);
// now add that unique style to the div
bar.classList.add(`barHeight${count}`);
// use standard style from css as well
bar.classList.add('sortBar');
// now add that div to the DOM
sortDisplay.appendChild(bar);
}
// clear container div and regenerate
function reset() {
cancelLast();
// clear all data within the container
sortDisplay.innerHTML = '';
// reset the count
count = 0;
// generate k bars
for (let i = 0; i < amount; i++) {
generateBar();
}
}
// when page is loaded reset
reset(amount);
// swap elements within the DOM
function swapElements(obj1, obj2) {
// create marker element and insert it above where obj1 is
var temp = document.createElement("div");
obj1.parentNode.insertBefore(temp, obj1);
// move obj1 to right before obj2
obj2.parentNode.insertBefore(obj1, obj2);
// move obj2 to right before where obj1 used to be
temp.parentNode.insertBefore(obj2, temp);
// remove temporary marker node
temp.parentNode.removeChild(temp);
}
// sort the divs within the DOM
async function sort(cancellationChecker) {
for (let i = 1; i < amount; i++) {
let j = i;
for (j; j > 0; j--) {
if (cancellationChecker()) return;
if (+document.querySelectorAll('.sortBar')[j].getAttribute('value') < +document.querySelectorAll('.sortBar')[j-1].getAttribute('value')) {
swapElements(document.querySelectorAll('.sortBar')[j], document.querySelectorAll('.sortBar')[j-1]);
await delay(DELAY_BETWEEN_SWAPS);
}
else {
break;
}
}
}
}
function btnSort() {
let cancelled = false;
cancelLast();
cancelLast = () => cancelled = true;
sort(() => cancelled);
}
// Button to run the sort function
button = document.querySelector('.button');
button.addEventListener('click', btnSort);
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
width: 100%;
}
.sortDisplay {
background-color: #305c50;
background-image: linear-gradient(28deg, #305c50 0%, #6ab19e 70%, #82d8a6 100%);
display: flex;
align-items: flex-end;
justify-content: space-between;
height: 100%;
width: 100%;
overflow: hidden;
}
.btn-container {
position: absolute;
right: 0;
bottom: 0;
margin: 25px;
}
.btn-container button {
padding: 25px;
}
.sortBar {
flex: 1;
background-color: #0007;
}
<div class="btn-container">
<button class="reset">reset</button>
<button class="button">button</button>
</div>
<div id="sortDisplay"class="sortDisplay"></div>