Можно ли оптимизировать переключение класса у элементов по клику

Всем привет, возможно вам сразу будет проще посмотреть демонстрацию кода чем читать мои устные объяснения, сам вопрос внизу этого текста. У меня есть 3 элемента. При клике у этих элементов переключаются классы(не обращайте внимания на название классов, тут важно то что классов 2 и они разные), работает это следующим образом, есть класс 'right' и 'out-left' При клике на кнопку, класс 'right' добавляется элементу-1, а класс 'out-left' элементу 2, при повторном клике класс 'right' удаляется у элемента-1, а класс 'out-left' удаляется у элемента-2, в этот же момент класс 'right' добавляется элементу-2, а класс 'out-left' добавляется элементу-3, соответственно если кликнуть ещё раз, то класс 'right' удаляется у элемента-2 и класс 'out-left' удаляется у элемента-3 и в это же время класс 'right' добавляется элементу-3, а класс 'out-left' добавляется элементу-1 и так по кругу.

Проблема в том что я это сделал максимально тупо, без возможности быстро добавить новый элемент(если его добавлять то понадобится еще много строк кода). Возможно ли как то это оптимизировать чтобы бесконечно можно было добавлять элементы? Может массив из элементов сделать и как-нибудь его перебирать и добавлять эти классы, ничего в голову не приходит. Спасибо если вдумались в мою писанину:)

let el1 = document.querySelector('.el-1');
let el2 = document.querySelector('.el-2');
let el3 = document.querySelector('.el-3');

let paintHandler = function() {
    if (el3.classList.contains('out-left')) {
        el3.classList.remove('out-left')
        el3.classList.add('right');
        el2.classList.remove('right')
        el1.classList.add('out-left');
        return;
    }

    if (!el1.classList.contains('right')){
        el1.classList.remove('out-left');
        el3.classList.remove('right')
        el1.classList.add('right');
        el2.classList.add('out-left');
        return;
    }
    if (el1.classList.contains('right')){
        el1.classList.remove('right');
        el2.classList.remove('out-left');
        el2.classList.add('right');
        el3.classList.add('out-left');
        return;
    }

    

}
.container {
    display: flex;
    gap: 5px;
}

.element {
    border: 4px solid black;
    padding: 5px;

}

button {
    margin-top: 15px;
}

.right {
    background-color: red;
}

.out-left {
    background-color: blue;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/css/style.css">
    <title>Slider</title>
</head>
<body>
<div class="container"> 
    <div class="el-1 element">
        <span>Элемент 1</span>
    </div>
    <div class="el-2 element">
        <span>Элемент 2</span>
    </div>
    <div class="el-3 element">
        <span>Элемент 3</span>
    </div>
</div> 

<button onclick="paintHandler()">Впёред</button>
    
<script src="/js/script.js"></script>
</body>
</html>


Ответы (1 шт):

Автор решения: Алексей Шиманский

Скрипт ниже работает с любым количеством элементов.

С массивом данных работать проще, чем с элементами DOM дерева, поэтому в нём занесены необходимые данные, производятся действия, а потом на основе данных в нём - рисуется что-то в элементы. Например на одной из итераций он будет выглядеть так:

['no-color', 'no-color', 'red', 'blue', 'no-color'];

В коде потом просто последний элемент перемещается на первую позицию и всё перерисовывается

const ELEMENT_COLOR_BLUE = 'blue';
const ELEMENT_COLOR_RED = 'red';

let elements = document.querySelectorAll('.element');
let elementsCount = elements.length;
// В массиве arr будут хранится цвета на тех индексах, элементы которых будут окрашиваться в 
// html разметке.... т.е. работает своего рода отражением разметки, но с данными по ним
let arr = Array.from({ length: elementsCount }).fill('no-color');
let initialClickWasMade = false;

let paintHandler = function() {
    // Если кликнули первый раз, то устанавливаем цвета в соответствующие блоки
    if (!initialClickWasMade) {
        arr[0] = ELEMENT_COLOR_RED;
        arr[1] = ELEMENT_COLOR_BLUE;
        initialClickWasMade = true;
    }
    
    // Просто у всех убираем классы окраски, чтобы не заморачиваться 
    // с проверкой есть у кого какой клас или нет
    elements.forEach(el => {
        el.classList.remove(ELEMENT_COLOR_BLUE);
        el.classList.remove(ELEMENT_COLOR_RED);
    });
    
    // берем цвета из массива, где в каждой из ячеек лежит наименование класса цвета
    arr.forEach((color, i) => {
        elements[i].classList.add(color);
        elements[i].classList.add(color);
    });   
    
    // Дальше просто в массиве последний элемент помещаем в начало
    let lastElement = arr.pop();
    arr.unshift(lastElement);
}
.container {
    display: flex;
    gap: 5px;
}

.element {
    border: 4px solid black;
    padding: 5px;

}

button {
    margin-top: 15px;
}

.right, .red {
    background-color: red;
}

.out-left, .blue {
    background-color: blue;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/css/style.css">
    <title>Slider</title>
</head>
<body>
<div class="container"> 
    <div class="el-1 element">
        <span>Элемент 1</span>
    </div>
    <div class="el-2 element">
        <span>Элемент 2</span>
    </div>
    <div class="el-3 element">
        <span>Элемент 3</span>
    </div>
     <div class="el-3 element">
        <span>Элемент 3</span>
    </div>
     <div class="el-3 element">
        <span>Элемент 3</span>
    </div>
     <div class="el-3 element">
        <span>Элемент 3</span>
    </div>
</div> 

<button onclick="paintHandler()">Впёред</button>
    
<script src="/js/script.js"></script>
</body>
</html>

→ Ссылка