Reputation: 183
I am trying to make a ball shooting game use only vanilla Javascript for fun.
I want to have 10 or much more circles moving randomly on my screen. In below code, I have 10 circles list on the left side of my screen, they all have same color and size, only the positions are different. This is my HTML:
body {
width: 100vw;
height: 100vh;
}
.circle {
/*
position: absolute;
top: 1px;
*/
width: 50px;
height: 50px;
color: transparent;
border: 2px solid red;
border-radius: 50%;
}
.circle:nth-child(1) {
position: absolute;
top: 1px;
}
.circle:nth-child(2) {
position: absolute;
top: 60px;
}
.circle:nth-child(3) {
position: absolute;
top: 120px;
}
.circle:nth-child(4) {
position: absolute;
top: 180px;
}
.circle:nth-child(5) {
position: absolute;
top: 240px;
}
.circle:nth-child(6) {
position: absolute;
top: 300px;
}
.circle:nth-child(7) {
position: absolute;
top: 360px;
}
.circle:nth-child(8) {
position: absolute;
top: 420px;
}
.circle:nth-child(9) {
position: absolute;
top: 480px;
}
.circle:nth-child(10) {
position: absolute;
top: 540px;
}
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
I am new to Front-end tech. Is there any efficient way to style the circles better than this? If I like to have 100 circles on the screen I don't want to create 100 classes and style them one by one...
Thanks
Upvotes: 0
Views: 98
Reputation: 253308
The easiest answer is, looking at your code, to use JavaScript's NodeList.prototype.forEach()
:
// using document.querySelectorAll() to find all elements
// matching the supplied CSS selector, and then
// NodeList.prototype.forEach() to iterate over each Node
// of that NodeList:
document.querySelectorAll('.circle').forEach(
// using an Arrow function expression;
// 'circle': a reference to the current Node of the NodeList,
// 'index': the index of the current Node in the NodeList:
// here we set the circle.style.top property to be equal to
// the result of 60 * index concatenated with the 'px' unit:
(circle, index) => circle.style.top = 60 * index + 'px'
);
document.querySelectorAll('.circle').forEach(
(circle, index) => circle.style.top = 60 * index + 'px'
);
body {
width: 100vw;
height: 100vh;
}
.circle {
position: absolute;
width: 50px;
height: 50px;
color: transparent;
border: 2px solid red;
border-radius: 50%;
}
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
Admittedly this does place the first .circle
element with its top: 0px
rather than 1px
, so it's entirely possible to revise the above approach to explicitly style the .circle
elements with top: 1px
and then use the JavaScript to style all .circle
elements except the first:
document.querySelectorAll('.circle + .circle').forEach(
(circle, index) => circle.style.top = 60 + (60 * index) + 'px'
);
document.querySelectorAll('.circle + .circle').forEach(
(circle, index) => circle.style.top = 60 + (60 * index) + 'px'
);
body {
width: 100vw;
height: 100vh;
}
.circle {
position: absolute;
top: 1px;
width: 50px;
height: 50px;
color: transparent;
border: 2px solid red;
border-radius: 50%;
}
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
Further to the above, using a templating language such as Vue (this still involves JavaScript):
// for something so simple Vue is - almost certainly -
// overkill, however: Vue is initialised (in this very
// simple case) as follows:
new Vue({
// 'el' takes a CSS selector to identify the
// elements in, or upon, which Vue should run:
'el': '.wrapper'
});
*,
::before,
::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.circle {
position: absolute;
width: 50px;
height: 50px;
border-radius: 50%;
border: 2px solid #f00;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js"></script>
<div class="wrapper">
<!--
here we define the element that will be repeated,
to repeat the element we use the v-for attribute,
here we use the 'i in 10' (i is the current number,
starting at 1, 10 is the end of the range); to adjust
the 'style' attribute, we preface the attribute with
the ':' character, and within that attribute we use:
`top: ${i * 60 - 60)px`
this is a JavaScript template literal syntax, in which
the 'i * 60 - 60' wrapped by '${...}' is interpolated
by Vue to generate the relevant values
-->
<div class="circle" v-for="i in 10" :style="`top: ${i * 60 - 60}px`"></div>
</div>
Upvotes: 1
Reputation: 1349
It would be better if you could create/append your balls to the body via javascript. Something like below.
var ball = document.createElement('div');
ball.className = 'circle';
document.body.appendChild(ball);
Then you can change each ball position randomly like below.
ball.style.position.top = <your_random_number>;
It would also better if you put position: absolute
in base .circle css selector.
Above code snippet is for one ball. You can simple extend it for more than one by justing pushing each created ball in array and then iterate over the array and append each one to the body.
Upvotes: 0