Как динамически у квиза вывести шаги и давать класс активному?

Ссылка скопирована
1 ответ

Есть квиз, что-то не как не додумаю как сделать без костылей. Нужно динамически вывести шаги (слева) и давать активному класс _active
snippet

Дополнительно:

Но и сейчас все на костылях: дублируется разметка (и есть шанс ошибиться), состояние квиза «живёт» в разметке. Ввод телефона не удобный. Компоненты отчего б не взять все готовые из какого-нибудь красивого ui-кита, и почему бы не переделать всё на React или Vue?
Данные квиза отдельно, разметка генерится из данных налету.

  • Сергей Соколов, фреймворки не знаю, как с бэка wordpress тоже не знаю данные в объекты передавать. поэтому делаю на разметке
  • Ответы:

    Так сделай хотя бы так же как у тебя уже сделано перелистывание вопросов.

    const quizzes = document.querySelectorAll(".calc__fields"); quizzes.forEach((quiz) => {   const questions = quiz.querySelectorAll(".fields__field"),     btnsPrev = quiz.querySelectorAll(".btn-prev"),     btnsNext = quiz.querySelectorAll(".btn--icon-next"),     stages = quiz.querySelectorAll(".fields__stage");   console.log(stages)    // progress   // const progressCount = questions.length;    btnsNext.forEach((btnNext, btnNextIndex) => {     btnNext.addEventListener("click", (e) => {       e.preventDefault();        questions[btnNextIndex].classList.remove("_active");       questions[btnNextIndex + 1].classList.add("_active");              stages[btnNextIndex].classList.remove("_active");       stages[btnNextIndex + 1].classList.add("_active");            });     if (!questions[btnNextIndex].classList.contains("_range")) {       btnNext.disabled = true;     }   });      btnsPrev.forEach((btnPrev, btnPrevIndex) => {     btnPrev.addEventListener("click", (e) => {       e.preventDefault();        questions[btnPrevIndex + 1].classList.remove("_active");       questions[btnPrevIndex].classList.add("_active");     });   });      questions.forEach((question, questionIndex) => {     if (questionIndex === 0) {       question.classList.add("_active");     } else {       question.classList.remove("_active");     }     question.addEventListener("change", (e) => {       const target = e.target,         inputsChecked = question.querySelectorAll("input:checked");       if (         inputsChecked.length > 0 ||         target.classList.contains("range__input")       ) {         btnsNext[questionIndex].disabled = false;       } else {         btnsNext[questionIndex].disabled = true;       }     });   }); });

    const quizzes = document.querySelectorAll(".calc__fields"); quizzes.forEach((quiz) => { const questions = quiz.querySelectorAll(".fields__field"), btnsPrev = quiz.querySelectorAll(".btn-prev"), btnsNext = quiz.querySelectorAll(".btn--icon-next"), stages = quiz.querySelectorAll(".fields__stage"); console.log(stages) // progress // const progressCount = questions.length; btnsNext.forEach((btnNext, btnNextIndex) => { btnNext.addEventListener("click", (e) => { e.preventDefault(); questions[btnNextIndex].classList.remove("_active"); questions[btnNextIndex + 1].classList.add("_active"); stages[btnNextIndex].classList.remove("_active"); stages[btnNextIndex + 1].classList.add("_active"); }); if (!questions[btnNextIndex].classList.contains("_range")) { btnNext.disabled = true; } }); btnsPrev.forEach((btnPrev, btnPrevIndex) => { btnPrev.addEventListener("click", (e) => { e.preventDefault(); questions[btnPrevIndex + 1].classList.remove("_active"); questions[btnPrevIndex].classList.add("_active"); }); }); questions.forEach((question, questionIndex) => { if (questionIndex === 0) { question.classList.add("_active"); } else { question.classList.remove("_active"); } question.addEventListener("change", (e) => { const target = e.target, inputsChecked = question.querySelectorAll("input:checked"); if ( inputsChecked.length > 0 || target.classList.contains("range__input") ) { btnsNext[questionIndex].disabled = false; } else { btnsNext[questionIndex].disabled = true; } }); }); });

    • Не уверен что это без костылей, но вроде работает
    • Как вариант, только как шаги js'ом выставить
    • Даниил Гладыш, Потому что когда отрисовываю шаги в questions.forEach, это уже будет не в области видимости
      stages[btnNextIndex].classList.remove("_active");       stages[btnNextIndex + 1].classList.add("_active");

      stages[btnNextIndex].classList.remove("_active"); stages[btnNextIndex + 1].classList.add("_active");

    • anmkh, Почему? Шаги как раз двигаются
    • Даниил Гладыш,
      Генерирую разметку из js и переключение уже не срабатывает
      const quizzes = document.querySelectorAll(".calc__fields"); quizzes.forEach((quiz) => {     const questions = quiz.querySelectorAll(".fields__field"),         btnsPrev = quiz.querySelectorAll(".btn-prev"),         btnsNext = quiz.querySelectorAll(".btn--icon-next"),         stagesWrapper = quiz.querySelector(".fields__stages");     stages = quiz.querySelectorAll(".fields__stage");     // progress     const progressCount = questions.length;      btnsNext.forEach((btnNext, btnNextIndex) => {         btnNext.addEventListener("click", (e) => {             e.preventDefault();              questions[btnNextIndex].classList.remove("_active");             questions[btnNextIndex + 1].classList.add("_active");             stages[btnNextIndex].classList.remove("_active");             stages[btnNextIndex + 1].classList.add("_active");         });         if (!questions[btnNextIndex].classList.contains("_range")) {             btnNext.disabled = true;         }     });     btnsPrev.forEach((btnPrev, btnPrevIndex) => {         btnPrev.addEventListener("click", (e) => {             e.preventDefault();             questions[btnPrevIndex + 1].classList.remove("_active");             questions[btnPrevIndex].classList.add("_active");             // count--;             // currentNum.innerHTML = count;         });     });     questions.forEach((question, questionIndex) => {         if (questionIndex === 0) {             question.classList.add("_active");         } else {             question.classList.remove("_active");         }         const count = questionIndex + 1;         if (count === 1) {             stagesWrapper.innerHTML += '<li class="fields__stage _active">' + "Шаг " + count + "</li>";         } else {             stagesWrapper.innerHTML += '<li class="fields__stage">' + "Шаг " + count + "</li>";         }         question.addEventListener("change", (e) => {             const target = e.target,                 inputsChecked = question.querySelectorAll("input:checked");             if (inputsChecked.length > 0 || target.classList.contains("range__input")) {                 btnsNext[questionIndex].disabled = false;             } else {                 btnsNext[questionIndex].disabled = true;             }         });     }); });

      const quizzes = document.querySelectorAll(".calc__fields"); quizzes.forEach((quiz) => { const questions = quiz.querySelectorAll(".fields__field"), btnsPrev = quiz.querySelectorAll(".btn-prev"), btnsNext = quiz.querySelectorAll(".btn--icon-next"), stagesWrapper = quiz.querySelector(".fields__stages"); stages = quiz.querySelectorAll(".fields__stage"); // progress const progressCount = questions.length; btnsNext.forEach((btnNext, btnNextIndex) => { btnNext.addEventListener("click", (e) => { e.preventDefault(); questions[btnNextIndex].classList.remove("_active"); questions[btnNextIndex + 1].classList.add("_active"); stages[btnNextIndex].classList.remove("_active"); stages[btnNextIndex + 1].classList.add("_active"); }); if (!questions[btnNextIndex].classList.contains("_range")) { btnNext.disabled = true; } }); btnsPrev.forEach((btnPrev, btnPrevIndex) => { btnPrev.addEventListener("click", (e) => { e.preventDefault(); questions[btnPrevIndex + 1].classList.remove("_active"); questions[btnPrevIndex].classList.add("_active"); // count--; // currentNum.innerHTML = count; }); }); questions.forEach((question, questionIndex) => { if (questionIndex === 0) { question.classList.add("_active"); } else { question.classList.remove("_active"); } const count = questionIndex + 1; if (count === 1) { stagesWrapper.innerHTML += '<li class="fields__stage _active">' + "Шаг " + count + "</li>"; } else { stagesWrapper.innerHTML += '<li class="fields__stage">' + "Шаг " + count + "</li>"; } question.addEventListener("change", (e) => { const target = e.target, inputsChecked = question.querySelectorAll("input:checked"); if (inputsChecked.length > 0 || target.classList.contains("range__input")) { btnsNext[questionIndex].disabled = false; } else { btnsNext[questionIndex].disabled = true; } }); }); });

    • anmkh, А зачем так делать? Твой первоначальный код кое-как работал, я немного его изменил -> начали двигаться шаги, замени просто то что было на то что я скинул
    • Даниил Гладыш, А если количество шагов может быть разным? Не на беке же через форич прогонять
    • anmkh, Ну так в комментариях тебе писали, что у тебя разметка несколько раз повторяется. Если уж исправлять это то не только шагами. Тебе нужно сделать шаблон, а вопросы, варианты ответов и итератор формы хранить в скрипте. Кнопкой прибавлять 1 к итератору и обращаясь к спискам менять вопрос, варианты ответов.
    • Даниил Гладыш, Ок, есть дока как мне из php вопросы и типы инпутов тянуть в js?
    • https/stackoverflow.com/questions/415868/get-variable-from-php-to-javascript
    • Сделай на базе слайдера - swiper, slick итп
    • Александр Васильев, Как вариант кстати. Не колхоз получится?
    • anmkh, всегда так делаю, там уже все готово
    • anmkh, могу пример в личку дать
    • Александр Васильев, Да на свайпере есть понимание как сделать, только пишут что данные нужно выносить. Я в принципе проблемы не вижу чтобы их не выносить, но опыта меньше и поэтому не знаю чем чревано держать все в разметке. Там же не проверяется корректность выбранного поля,а просто форма с шагами
    • anmkh, да, все это обернуть в форму, на финале кнопку next скрыть и submit открыть. Также сделать запрет на отправку через enter, пока до конца не дойдешь либо вообще.
    • Александр Васильев, Даниил Гладыш, ребята, вы настолько дали расширенный ответ, что реально, я лично, не могу пройти мимо ваших ответов.
      Для anmkh, осталось только правильно обернуть всё это в код. В логический и правильный, но это уже другая история..
      Вам же только БРАВО!.
      anmkh, вы можете отслеживать все события, которые возникают непосредственно в форме.
      Слушай форму, а не то, что вокруг неё. Инициализируй скрипт только тогда, когда форма доступна. Инициализация скрипта подразумевает под собой то, что ты навешиваешь события сам на все контролы, которые ты сам хочешь отследить. И только ты сам можешь от этих событий отписаться или переопределить эти события под своё усмотрение.
      Может быть я сложно навожу на мысль, но твой ход событий правильный.
    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Мария Код Ответ

    Для динамического вывода шагов в квизе и добавления класса активному шагу, можно воспользоваться следующим подходом. Для начала, создадим HTML структуру для квиза, где каждый шаг будет представлен отдельным элементом. Например:

    <div class="quiz">
        <div class="step active">Шаг 1</div>
        <div class="step">Шаг 2</div>
        <div class="step">Шаг 3</div>
        <div class="step">Шаг 4</div>
    </div>

    <div class="quiz"> <div class="step active">Шаг 1</div> <div class="step">Шаг 2</div> <div class="step">Шаг 3</div> <div class="step">Шаг 4</div> </div>

    Затем, добавим JavaScript код для обработки событий и динамического изменения классов:

    document.addEventListener('DOMContentLoaded', function() {
        const steps = document.querySelectorAll('.step');
     
        steps.forEach((step, index) =&gt; {
            step.addEventListener('click', () =&gt; {
                steps.forEach(s =&gt; s.classList.remove('active'));
                step.classList.add('active');
            });
        });
    });

    document.addEventListener('DOMContentLoaded', function() { const steps = document.querySelectorAll('.step'); steps.forEach((step, index) =&gt; { step.addEventListener('click', () =&gt; { steps.forEach(s =&gt; s.classList.remove('active')); step.classList.add('active'); }); }); });

    В данном примере, при клике на каждый шаг квиза, удаляем класс 'active' у всех шагов и добавляем его только активному шагу. Таким образом, можно отслеживать текущий шаг квиза и стилизовать его соответственно.

    Также, можно добавить дополнительную логику для переключения шагов в зависимости от действий пользователя или других условий. Например, можно добавить проверку на заполнение всех обязательных полей перед переходом к следующему шагу.

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

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно