最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to loop through an array to change background colours using JS? - Stack Overflow

programmeradmin4浏览0评论

Firstly, I know it would be more simple to achieve this using CSS but I am really trying to wrap my head around looping with JS as it is a new concept for me

What I want to happen is for the 'bg' class to loop through a number of background colours once

My code does not currently work would very much appreciate some direction :)

HTML

<div class="bg"></div>

CSS

.bg {
   width: 100%;
   height: 100%;
}

JS

var bg = document.getElementByClassName('bg');
var colours = ["#CCCDFF", "#BAC7E8", "#D9EEFF", "#BADFE8"];
  for (i = 0; i < colours.length; i++) {
    setInterval(change, 200); 
    function change() {
      bg.style.background = colours;
    }
  }

Firstly, I know it would be more simple to achieve this using CSS but I am really trying to wrap my head around looping with JS as it is a new concept for me

What I want to happen is for the 'bg' class to loop through a number of background colours once

My code does not currently work would very much appreciate some direction :)

HTML

<div class="bg"></div>

CSS

.bg {
   width: 100%;
   height: 100%;
}

JS

var bg = document.getElementByClassName('bg');
var colours = ["#CCCDFF", "#BAC7E8", "#D9EEFF", "#BADFE8"];
  for (i = 0; i < colours.length; i++) {
    setInterval(change, 200); 
    function change() {
      bg.style.background = colours;
    }
  }
Share Improve this question asked Dec 4, 2019 at 22:01 Burger SashaBurger Sasha 1756 silver badges24 bronze badges 2
  • Does this answer your question? Simple way to synchronously execute code after setTimout() code is done – Rickard Elimää Commented Dec 4, 2019 at 22:03
  • They all run at 200 milliseconds. 200 * (i+1) – epascarello Commented Dec 4, 2019 at 22:03
Add a ment  | 

4 Answers 4

Reset to default 5

There are 3 big problems with this line:

var bg = document.getElementByClassName('bg');
  1. The method is getElementsByClassName(). You missed an "s".
  2. .getElementsByClassName() returns a node list (collection) of all matching elements. The collection doesn't have a style property, only individual elements will. You'd have to extract an element from the collection first and then access it's style.
  3. .getElementsByClassName() returns a "live" node list, which hurts performance quite a bit. It's a very old API and shouldn't be used in 2019.

Next, because the interval timer will run continuously at the specified interval, the loop is not required. The repeating nature of the timer acts as a loop.

Next, in your CSS, you specify your element's size using percents, but percents have to be relative to something else, otherwise they won't work. If you want the element to be as big as the page, use vw and vh (Viewport Width and Viewport Height).

// Don't use `.getElementsByClassName()`
var bg = document.querySelector('.bg');
var colours = ["#CCCDFF", "#BAC7E8", "#D9EEFF", "#BADFE8"];
var index = 0; // Will keep track of which color to use

function change() {
  // If we have run out of colors, stop the timer
  if(index >= colours.length){ clearInterval(timer); }
  
  // Set the color and increment the index
  bg.style.backgroundColor = colours[index++];
}

// Start the timer but get a reference to it 
// so we can stop it later
var timer = setInterval(change, 200); 
.bg {
   width: 100vw;
   height: 100vh;
}
<div class="bg"></div>

You missed an s in getElementsByClassName, and since it returns multiple DOM elements, you need to select the first one with [0], or, as suggested by @ScottMarcus, simply use querySelector which will return the first element matching the selector you pass to it.

And when using setInterval inside a loop with the same delay, they're all going to trigger at the same time. Here is another approach using setTimeout:

var bg = document.querySelector('.bg');
var colours = ["#CCCDFF", "#BAC7E8", "#D9EEFF", "#BADFE8"];

chainColours(colours);

function chainColours(colours) {
  if (colours.length) {
    setColour(colours[0]);
    setTimeout(function() {
      chainColours(colours.slice(1)); // Repeat with all colours except the first one
    }, 200);
  }
}

function setColour(colour) {
  bg.style.background = colour;
}
.bg {
  width: 100px;
  height: 100px;
}
<div class="bg"></div>

Here, we're using a recursive function (a function which calls itself).

The first time we call it, we pass it the entire array of colours. The if condition will pass, because colours.length will be truthy (different than 0).

We set the bg colour to the first colour in that Array, using the setColour() function.

And then, using setTimeout, we wait 200ms to call the function again, but passing the Array without the first element, using slice.

It will go on until there are no elements left in that passed Array. Then, the if condition will not pass, and it will stop.

const bg = document.querySelector('.bg');
const colours = ["#CCCDFF", "#BAC7E8", "#D9EEFF", "#BADFE8"];

(async () => {
  for (const [index, colour] of colours.entries()) {
    await new Promise(resolve => setTimeout(() => bg.style.background = colour, 200))
  }
})()

  • Use const (if variable should not be redefined) or let instead of var.
  • I replaced getElementByClassName with querySelector, as the former returns a list of elements and querySelector returns one
  • The self-invoking "async" function is used to make await keyword available. It awaits an asynchronous task.
  • The async task is the promise, which resolves after 200ms. Then the next async task is awaited.

setInterval will schedule a function to be called after a certain interval. It is non-blocking, so execution will proceed immediately after the function is queued. In this case, you're scheduling all four color changes to happen after 200 milliseconds, so the callbacks will be fired simultaneously.

Instead, you could do something like this: setInterval(change, 200 * i)

发布评论

评论列表(0)

  1. 暂无评论