Перебираем классы в HTML-элементе. Объясняем как это делать

Так есть же функция toggle()?


Да, в самом Жабаскрипте есть такая функция, но она позволяет переключаться только между 1-2 классами.

А что делать, когда нужно переключаться между 3 и более классами? Давай разбираться



Наш красивый и полезный канал:3

Перебираем классы в HTML-элементе. Объясняем как это делать Программирование, IT, Javascript, HTML, Frontend, Web-программирование, Веб-разработка, Гифка, Длиннопост

Скажем, у вас есть три класса HTML, и элемент DOM должен иметь только один из них одновременно:

<div class="state-1"></div> 
<div class="state-2"></div>
<div class="state-3"></div>

Теперь ваша задача — вращать их. То есть циклически перебирать классы HTML-элемента. Когда происходит какое-то событие, если на нем есть элемент state-1, удалите state-1и добавьте state-2. Если он есть state-2, удалите это и добавьте state-3. В последнем состоянии удалите его и вернитесь к state-1.

Примечательно, что здесь речь идет о классах 3+. В DOM есть .classList.toggle()функция, даже та, которая принимает условное выражение в качестве второго параметра, но она в первую очередь полезна в ситуации включения/выключения двух классов, а не циклического переключения между классами.

Почему? Есть ряд причин. Изменение имени класса дает вам много возможностей для изменения стиля элементов в DOM, а подобное управление состоянием является краеугольным камнем современной веб-разработки. Но если быть точным, в моем случае я хотел сделать анимацию FLIP , где я бы изменил макет и запускал анимацию движения между различными состояниями.
Будьте осторожны с существующими классами! Я видел некоторые идеи, которые перезаписывали .className, что недружественно по отношению к другим классам, которые могут быть в элементе DOM. Все это «безопасный» выбор для циклического прохождения классов таким образом.

Подробный оператор if/else для циклического перебора классов


Это то, что я сделал сначала, чтобы пройтись по классам. Так работает мой мозг. Просто напишите очень конкретные инструкции для того, что именно вы хотите, чтобы произошло:

if (el.classList.contains("state-1")) {
el.classList.remove("state-1");
el.classList.add("state-2");
} else if (el.classList.contains("state-2")) {
el.classList.remove("state-2");
el.classList.add("state-3");
} else {
el.classList.remove("state-3");
el.classList.add("state-1");
}

Я не возражаю против многословия здесь, потому что мне очень ясно, что происходит, и мне будет легко вернуться к этому коду и, как говорится, «рассуждать об этом». Многословие можно считать проблемой — наверняка есть способ перебирать классы с меньшим количеством кода. Но большая проблема в том, что он не очень расширяемый. Нет никакого подобия конфигураций (например, легко изменить имена классов) или простого способа добавить классы в партию или удалить их.


Мы могли бы использовать константы, по крайней мере:

const STATE_1 = "state-1";
const STATE_2 = "state-2";
const STATE_3 = "state-3";
if (el.classList.contains(STATE_1)) {
el.classList.remove(STATE_1);
el.classList.add(STATE_2);
} else if (el.classList.contains(STATE_2)) {
el.classList.remove(STATE_2);
el.classList.add(STATE_3);
} else {
el.classList.remove(STATE_3);
el.classList.add(STATE_1);
}

Но это не сильно отличается или лучше.

RegEx от старого класса, увеличение состояния, затем повторное добавление


Этот исходит от Таба Аткинса . Так как мы знаем формат класса, state-Nмы можем искать его, выдергивать число, использовать небольшую троицу для его увеличения (но не выше самого высокого состояния), а затем добавлять/удалять классы как способ циклического прохождения. их:


const oldN = +/\bstate-(\d+)\b/.exec(el.getAttribute('class'))[1];
const newN = oldN >= 3 ? 1 : oldN+1;
el.classList.remove(`state-${oldN}`);
el.classList.add(`state-${newN}`);


Найдите индекс класса, затем удалите/добавьте


Куча методов для циклического переключения классов сосредоточена на настройке массива классов заранее. Это действует как конфигурация для циклического переключения классов, и я думаю, что это разумный способ сделать это. Получив это, вы можете найти соответствующие классы для их добавления и удаления. Это от Кристофера Кирка-Нильсена :


const classes = ["state-1", "state-2", "state-3"];
const activeIndex = classes.findIndex((c) => el.classList.contains(c));
const nextIndex = (activeIndex + 1) % classes.length;
el.classList.remove(classes[activeIndex]);
el.classList.add(classes[nextIndex]);

У Кристофера была хорошая идея сделать технику добавления/удаления короче. Оказывается, это одно и то же…

el.classList.remove(classes[activeIndex]);
el.classList.add(classes[nextIndex]);

// Does the same thing.
el.classList.replace(classes[activeIndex], classes[nextIndex]);

У Mayank была похожая идея для циклического переключения классов путем поиска класса в массиве, только вместо использования classList.contains(), вы проверяете классы, находящиеся в настоящее время в элементе DOM, с тем, что находится в массиве.


const states = ["state-1", "state-2", "state-3"];
const current = [...el.classList].find(cls => states.includes(cls));
const next = states[(states.indexOf(current) + 1) % states.length];
el.classList.remove(current);
el.classList.add(next);

Варианты этого были наиболее распространенной идеей. Вот Jhey и вот Mike Wagz, которые настраивают функции для движения вперед и назад.

Каскадные операторы замены


Говоря об этом replaceAPI, у Криса Кало была умная идея , когда вы связываете их с orоператором и полагаетесь на тот факт, что он возвращает true/false, работает он или нет. Итак, вы делаете все три, и один из них будет работать!


el.classList.replace("state-1", "state-2") ||
el.classList.replace("state-2", "state-3") ||
el.classList.replace("state-3", "state-1");

Николо Рибаудо пришел к такому же выводу.

Просто пролистайте номера классов


Если вы предварительно настроили предварительную настройку 1, вы можете циклически переключаться между классами 1-3 и добавлять/удалять их на основе этого. Это от Тимоти Леверета , который перечисляет еще один подобный вариант в том же твите.

// Assumes a `let s = 1` upfront
el.classList.remove(`state-${s + 1}`);
s = (s + 1) % 3;
el.classList.add(`state-${s + 1}`);


Вместо этого используйте data-*атрибуты

Атрибуты данных имеют одинаковую силу специфичности, поэтому у меня нет проблем с этим. На самом деле они могут быть более понятными с точки зрения обработки состояния, но, что еще лучше, у них есть специальный API , которым приятно манипулировать. У Мунаввара Фироза была идея , которая сводится к одной строчке:


el.dataset.state = (+el.dataset.state % 3) + 1

Конечный автомат атрибутов данных


Вы можете рассчитывать на то, что Дэвид Хуршид подготовит конечный автомат:


const simpleMachine = {
"1": "2",
"2": "3",
"3": "1"
};
el.dataset.state = simpleMachine[el.dataset.state];

Вам почти наверняка понадобится функция


Дайте себе немного абстракции, не так ли? Многие идеи были написаны таким образом, но пока я переместил его, чтобы сосредоточиться на самой идее. Здесь я оставлю функцию. Это от Андреа Джаммарки , в котором уникальная функция для циклического переключения классов настраивается заранее, а затем вы вызываете ее по мере необходимости:


const rotator = (classes) => ({classList }) => {
const current = classes.findIndex((cls) => classList.contains(cls));
classList.remove(...classes);
classList.add(classes[(current + 1) % classes.length]);
};
const rotate = rotator(["state-1", "state-2", "state-3"]);
rotate(el);
Я слышал от Кайла Симпсона, у которого была такая же идея, почти персонаж за персонажем.


А вот демонстрационная ручка со всем кодом для каждого примера. Они пронумерованы, поэтому, чтобы проверить еще один, закомментируйте тот, который не закомментирован, и раскомментируйте другой пример:

https://codepen.io/chriscoyier/pen/xxXeXPN

Web-технологии

460 постов5.8K подписчиков

Добавить пост

Правила сообщества

1. Не оскорблять других пользователей

2. Не пытаться продвигать свои услуги под видом тематических постов

3. Не заниматься рекламой

4. Никакой табличной верстки

5. Тег сообщества(не обязателен) pikaweb