我正在使用javascript制作一个程序,该程序将在一段时间后更改元素的CSS样式(在这种情况下为背景色),类似于交通灯。
问题是这样的:单击按钮时,将进入按钮的onclick侦听器功能。在该函数中,有for循环遍历每个单元格并更改其颜色。每次通过循环应该更新单元格颜色之一,但不是。实际发生的是在按钮的onclick侦听器功能完成后,所有单元格都将更新。
这里是我制作的https://jsfiddle.net/lilweege/4291vjto/6/的简短版本的链接
let main = document.getElementById('main')
// create 'cells' which are just empty divs (refer to css styles above)
let cells = []
for (let x = 0, numCells = 15; x < numCells; x++) {
let cell = document.createElement("DIV")
cell.setAttribute('class', 'cell')
cells.push(cell)
main.appendChild(cell)
}
// create button to run main logic
const run = document.createElement("BUTTON")
run.innerHTML = 'change colors'
run.addEventListener('click', function() {
console.log('starting program');
// reset all cell colors
for (let cell of cells) {
cell.style.background = 'white'
}
for (let cell of cells) {
// change color of cell
cell.style.background = `hsl(${cells.indexOf(cell) * (360 / cells.length)}, 100%, 50%)`
// halt program for 500ms
sleep(100)
}
console.log('done');
})
main.appendChild(run)
// sleep function halts entire program during period of ms
function sleep(milliseconds) {
console.log(`waiting ${milliseconds} milliseconds`);
const start = Date.now();
let current = null;
do {
current = Date.now();
} while (current - start < milliseconds);
}
.main {
display: flex;
}
.cell {
width: 20px;
height: 20px;
border: 1px solid black;
margin: 1px;
}
<div id="main" class="main"></div>
[添加元素,更改某些其他属性(例如innerHTML或DOM中的其他更改时,也是这种情况。
另外,我也不怀疑我的'sleep'函数是问题所在,因为它所做的只是暂停浏览器中的整个程序,直到经过了毫秒的时间(它调用Date.now()直到当前时间和开始时间大于传入的数量。
任何指针或解决方案将不胜感激,谢谢!
您的sleep
功能是问题。它半永久运行blocking循环。当前选项卡(或框架)的所有资源都将用于解决该循环,因此一旦完成,事件循环就可以继续并开始渲染。但是,如果嵌套循环(和事件侦听器)直到10秒钟后才解决,浏览器甚至在10秒钟后甚至无法start更新显示。
等待使用setTimeout
的Promise-setTimeout
不会阻塞处理或渲染,不像经过数万次迭代的循环:
const sleep = ms => new Promise(res => setTimeout(res, ms));
const main = document.getElementById('main')
const cells = []
for (let x = 0, numCells = 20; x < numCells; x++) {
const cell = document.createElement("DIV")
cell.setAttribute('class', 'cell')
cells.push(cell)
main.appendChild(cell)
}
const run = document.createElement("BUTTON")
run.innerHTML = 'change colors'
run.addEventListener('click', async function() {
for (let cell of cells) {
cell.style.background = `hsl(${cells.indexOf(cell) * (360 / cells.length)}, 100%, 50%)`
await sleep(500)
}
console.log('done');
})
main.appendChild(run)
.main {
display: flex;
}
.cell {
width: 20px;
height: 20px;
border: 1px solid black;
margin: 1px;
}
<div id="main" class="main"></div>
几乎[有充分的理由使用while
循环来等待Date.now()
达到阈值-这在计算上非常昂贵,对用户不友好(因为框架无法与之交互)期间),并且可能会产生意想不到的结果(例如您在这里遇到的情况)。
CertainPerformance响应速度比我快,而我正在同一边努力。
我刚刚对代码做了一些改进,我也认为最好在上色之前睡个好觉。const main = document.getElementById('main')
, cells = []
, numCells = 16
, run = document.createElement('button')
, sleep = ms => new Promise(res => setTimeout(res, ms))
;
let InOut = 0 // to reverse colors order
;
run.textContent = 'set colors'
;
for (let x=0; x < numCells; x++) // create 'cells' which are just empty divs (refer to css above)
{
cells[x] = main.appendChild(document.createElement('div'))
}
main.appendChild(run) // button to run main logic
;
run.onclick = async _=>
{
for (let cell of cells)
{ cell.style.backgroundColor = null }
for (let x in cells)
{
await sleep(200)
cells[x].style.backgroundColor = `hsl(${(Math.abs(InOut-x)) *(360 /numCells)}, 100%, 50%)`
}
InOut = InOut ? 0 : (numCells-1)
}
#main {
display: flex;
}
#main div {
display: inline-block;
width: 1.2em;
height: 1.2em;
border: 1px solid black;
margin: .1em;
background-color: white;
}
#main button {
margin-left:.3em
}
<div id="main"></div>