Arrow elements
There are two elements for the arrows, and presuming there is only one of each type (i.e. one left, one right) then it would be more appropriate to use an id attribute for distinguishing between those two.
Instead of
<div class="arrow-left arrow"></div>
<div class="arrow-right arrow"></div>
use the id attribute:
<div class="arrow" id="arrow-left"></div>
<div class="arrow" id="arrow-right"></div>
And instead of selecting elements by class name and taking the first one:
var leftArrow = document.getElementsByClassName('arrow')[0];
var rightArrow = document.getElementsByClassName('arrow')[1];
select them using document.getElementById()
:
var leftArrow = document.getElementById('arrow-left');
var rightArrow = document.getElementById('arrow-right');
Obviously this would require the CSS to be updated as well.
Direction parameter
There are only two possible values for direction, so it could be changed to a boolean like forward
that defaults to true
(default parameters is a feature of ecmascript-6 so be aware of the browser compatibility).
function carousel(forward = true) {
if (forward) {
//move forward
}
else {
//move backward
}
Simplify onclick event handlers
After making the first parameter for carousel
a boolean that defaults to true
(for the direction), the onclick
handlers can be simplified to function references. false
can be tied to the leftArrow handler by employing a partially applied function with Function.bind()
leftArrow.onclick = carousel.bind(null, false);
rightArrow.onclick = carousel;
If there was a need to have multiple event handlers on each element then addEventListener()
could be used:
leftArrow.addEventListener('click', carousel.bind(null, false));
rightArrow.addEventListener('click', carousel);
Simplify logic for current and next
Instead of looping through the reviews, select the elements that have class name show
(should only be one):
var shownReviews = document.getElementsByClassName('show');
That will be a live HTMLCollection, meaning that it updates as the DOM is updated, so there is no need to re-query it.
Then you can utilize shownReviews[0]
- this can be used to set currentReview
. Then when forward
is true
the value for nextReview
can be set utilizing nextElementSibling
or if that is null
using parentElement.firstElementChild
(and conversely using previousElementSibling
and lastElementChild
when forward
is false
).
function carousel(forward = true) {
currentReview = shownReviews[0];
if (forward) {
nextReview = currentReview.nextElementSibling || currentReview.parentElement.firstElementChild;
}
else {
nextReview = currentReview.previousElementSibling || currentReview.parentNode.lastElementChild;
}
currentReview.classList.remove("show");
nextReview.classList.add("show");
}
Simplify CSS
The following styles can be moved out of each of the rulesets for the arrows and moved into the ruleset for .arrow
:
width: 0;
height: 0;
border: 10px solid transparent;
Then the rulesets for the arrows becomes a single style:
#arrow-left {
border-right: 10px solid black;
}
#arrow-right {
border-left: 10px solid black;
}
The margin styles for .arrow
can be combined to a single style using two values:
margin: 0 25vw; /* top & bottom: 0, left & right: 25vw */
Rewrite
Below is simplified code using the advice above.
var shownReviews = document.getElementsByClassName('show');
var leftArrow = document.getElementById('arrow-left');
var rightArrow = document.getElementById('arrow-right');
var currentReview;
var nextReview;
function carousel(forward = true) {
currentReview = shownReviews[0];
if (forward) {
nextReview = currentReview.nextElementSibling || currentReview.parentElement.firstElementChild;
}
else {
nextReview = currentReview.previousElementSibling || currentReview.parentNode.lastElementChild;
}
currentReview.classList.remove("show");
nextReview.classList.add("show");
}
leftArrow.onclick = carousel.bind(null, false);
rightArrow.onclick = carousel;
* {
font-family: Arial;
}
.carousel {
display: flex;
align-items: center;
justify-content: center;
}
.review {
display: none;
text-align: center;
}
.show {
display: block;
}
.arrow {
border: 10px solid transparent;
width: 0;
height: 0;
margin: 0 25vw;
}
#arrow-left {
border-right: 10px solid black;
}
#arrow-right {
border-left: 10px solid black;
}
<div class="carousel">
<div class="arrow" id="arrow-left"></div>
<div class="reviews">
<div class="review show">
<h1 class="title">Title1</h1>
</div>
<div class="review">
<h1 class="title">Title2</h1>
</div>
<div class="review">
<h1 class="title">Title3</h1>
</div>
</div>
<div class="arrow" id="arrow-right"></div>
</div>
classList
, but not e.g. thelet
keyword. What environments/browsers would you like to support? \$\endgroup\$