Reputation: 1336
I have a couple thousand elements on a page that should have their CSS class changed upon the pressing of a button. Currently I have js code like the following:
for each (var id in list) {
var element = document.querySelector('[data-id="' + id + ']');
element.className = 'myClass';
}
In IE, this takes almost 20 seconds. I did some profiling, and it simply seems that the .className operation takes like half a millisecond; that along with garbage collection is what makes it take so long. I'm not sure if .className is causing a reflow or not.
Either way, how can I accomplish this task faster than I currently am?
Upvotes: 1
Views: 649
Reputation: 24241
I would make the CSS do all the hard work..
Just have some sort of parent, add a class to this and make your CSS target it.
eg.
document.querySelector("button").onclick = function () {
document.body.classList.toggle("button-clicked");
}
[data-id] {
background-color: yellow;
}
.button-clicked [data-id] {
background-color: pink;
}
<div data-id="1">One</div>
<div data-id="2">Two</div>
<div data-id="3">Three</div>
<div data-id="4">Four</div>
<div data-id="5">Five</div>
<button>Click Me</button>
If doing this CSS only is not an option, the best way to update the DOM is to do it detached,. Here is an example that creates 10,000 div's, and on the button click it randomly toggles the selected class of each one, but before doing this will temporarily detach them from the DOM, and then reattach after flipping the classes.
var container = document.querySelector(".container");
function addLine (txt) {
var div = document.createElement("div");
div.innerText = txt;
div.classList.add("line");
container.appendChild(div);
}
for (var l = 1; l <= 10000; l += 1) {
addLine("This is Line " + l + ", and some extra text");
}
document.querySelector("button").onclick = function () {
//temporally remove from DOM
container.parentNode.removeChild(container);
//all DOM methods here on conatiner should now be fast
//as there is no UI updates required..
var lines = container.querySelectorAll(".line");
for (var l = 0; l < lines.length; l ++) {
var e = lines[l];
if (Math.random() > 0.5)
e.classList.toggle("selected");
};
//Ok done, lets now put it back into the DOM
document.body.appendChild(container);
}
.line {
background-color: yellow;
}
.line.selected {
background-color: red;
}
<button>toggle class</button>
<div class="container">
</div>
Upvotes: 2