Возникли проблемы с созданием многошаговой формы с помощью карусели Slick. Мне чего-то не хватает в моем JavaScript

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

Я нашел веб-сайт, который делает почти то, что я хочу — https://www.gruntstyle.com/pages/club-grunt-style

Вот что у меня есть на данный момент - https://codepen.io/Alex-Baker-the-decoder/pen/MWxdKBa

$(document).ready(function () {
    // Define products
    const products = [
      {
        gender: "male",
        size: "s",
        product: "SPIKE SHIRT BOX",
        billing: "1st Month",
        productName: "Men’s Small Shirt - Monthly",
        link: ""
      },
      {
        gender: "female",
        size: "2XL",
        product: "shirt",
        billing: "monthly",
        productName: "Women’s 2XL Shirt - Monthly",
        link: ""
      }
    ];
  
    // Hide all steps except the first one initially
    $(".join-club-steps:not(:first)").hide();
  
    // When a radio button or select option is changed
    $('input[type = "radio"]').on("change", function () {
      var currentStep = $(this).closest(".join-club-steps");
      var nextStep = currentStep.next(".join-club-steps");
  
      // Show final slide if on the last step and valid
      if (nextStep.length === 0 && isStepValid(currentStep)) {
        showFinalSlide();
      } else {
        navigateSteps(this, "next");
      }
    });
  
    // Function to check if the step is valid
    function isStepValid(step) {
      var stepId = step.attr("id");
      switch (stepId) {
        case "join-step-gender":
          return $('input[name = "gender"]:checked').length > 0;
        case "join-step-size":
          return $('input[name = "size"]:checked').length > 0;
        case "join-step-product":
          return $('input[name = "product"]:checked').length > 0;
        case "join-step-billing":
          return $('input[name = "billing"]:checked').length > 0;
        default:
          return true;
      }
    }
  
    // Function to display the final slide with user selections
    function showFinalSlide() {
      var selectedGender = $('input[name = "gender"]:checked').val();
      var selectedSize = $('input[name = "size"]:checked').val();
      var selectedProduct = $('input[name = "product"]:checked').val();
      var selectedBilling = $('input[name = "billing"]:checked').val();
  
      // Update final slide with user's selections
      $("#selectedGender").text(selectedGender);
      $("#selectedSize").text(selectedSize);
      $("#selectedProduct").text(selectedProduct);
      $("#selectedBilling").text(selectedBilling);
  
      // Hide all steps and show final slide
      $(".join-club-steps").hide();
      $(".final-slide").show();
    }
  
    // Function to navigate steps
    function navigateSteps(element, direction) {
      var currentStep = $(element).closest(".join-club-steps");
      var stepIndex = $(".join-club-steps").index(currentStep) + 1; // Get current step index
      var targetStepIndex = direction === "next" ? stepIndex + 1 : stepIndex - 1;
  
      if (
        direction === "next" &&
        targetStepIndex <= $(".join-club-steps").length
      ) {
        showStep(targetStepIndex);
      }
    }
  
    // Function to show a specific step
    function showStep(stepNumber) {
      $(".join-club-steps").hide(); // Hide all steps
      $(".join-club-steps")
        .eq(stepNumber - 1)
        .show(); // Show the target step
      highlightCurrentStep(stepNumber);
    }
  
    // Function to highlight the current step in the progress bar
    function highlightCurrentStep(stepNumber) {
      $(".circle").removeClass("active"); // Remove active class from all circles
      $(".circle[data-step='" + stepNumber + "']").addClass("active"); // Add active class to the current circle
    }
  
    // Navigate to a specific step by clicking on the progress bar
    function navigateToStep(stepNumber) {
      showStep(stepNumber);
    }
  
    // Reset button functionality
    $("#reset-btn").click(function () {
      resetForm();
    });
  
    // Function to reset the form and go back to the first step
    function resetForm() {
      $('input[type = "radio"]').prop("checked", false);
      $("select").val($("select option:first").val());
      showStep(1); // Show the first step
    }
  
    // Initial setup
    highlightCurrentStep(1); // Highlight step 1
  });
/* Center everything */
.container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 1500px;
  background-color: #000;
  padding-bottom: 100px;
}

/* Style each step */
.join-club-steps {
  background-color: #fff;
  padding: 20px;
  border: 0px solid #ddd;
  border-radius: 8px;
  background-color: #000;
  margin-bottom: 20px;
  color: #fff;
}

/* Style the progress bar */
#join-club-progress-bar {
  display: flex;
  justify-content: center;
  align-items: center;
}

#join-club-progress-bar ul {
  list-style: none;
  padding: 0;
  display: flex;
}

#join-club-progress-bar ul li {
  margin: 0 10px;
}

.circle {
  width: 40px;
  height: 40px;
  background-color: #ddd;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-weight: bold;
  font-size: 20px;
  color: #f1402b;
  cursor: pointer;
}

.active {
  background-color: #f1402b;
  color: #fff;
}
.gender_male {
  font-size: 25px;
  border: solid 2px #fff;
  padding: 25px;
  color: #fff;
}
.gender_male:hover {
  font-size: 25px;
  border: solid 2px #f1402b;
  padding: 25px;
  cursor: none !important;
  background-color: #f1402b;
}
.gender_female {
  font-size: 25px;
  border: solid 2px #fff;
  padding: 25px;
  color: #fff;
}
.gender_female:hover {
  font-size: 25px;
  border: solid 2px #f1402b;
  padding: 25px;
  cursor: none !important;
  background-color: #f1402b;
}
.size_club {
  font-size: 40px;
  border: solid 2px #fff;
  padding: 25px;
  color: #fff;
}
.size_club:hover {
  font-size: 40px;
  border: solid 2px #f1402b;
  padding: 25px;
  cursor: none !important;
  background-color: #f1402b;
}
.product_club {
  font-size: 25px;
  border: solid 2px #fff;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  color: #fff;
}
.product_club:hover {
  font-size: 25px;
  border: solid 2px #f1402b;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  cursor: none !important;
  background-color: #f1402b;
}
.billing_club {
  font-size: 25px;
  border: solid 2px #fff;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  color: #fff;
}
.billing_club:hover {
  font-size: 25px;
  border: solid 2px #f1402b;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  cursor: none !important;
  background-color: #f1402b;
}
#product_detail_club {
  font-size: 14px;
  text-align: center;
  color: #fff;
}
.feq_club {
  font-size: 25px;
  border: solid 2px #fff;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  color: #fff;
}
.feq_club:hover {
  font-size: 25px;
  border: solid 2px #f1402b;
  padding: 25px;
  text-align: center;
  max-width: 280px;
  cursor: none !important;
  background-color: #f1402b;
}
#feq_detail_club {
  font-size: 14px;
  text-align: center;
  color: #fff;
}
.hide_radio {
  display: none;
}
button,
input,
select,
textarea {
  font-family: inherit;
  font-size: 25px;
  line-height: inherit;
  background-color: #f1402b;
  color: #fff;
  width: 100%;
  margin-bottom: 10px;
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div id = "steps-container" class = "container">
<img src = "https://ucarecdn.com/ffcf27ab-90b2-46ac-ae8d-83b11d8ada7c/-/format/auto/-/preview/3000x3000/-/quality/lighter/ClubAdx%20Logo%20w%20box.png" width = "500">
<div id = "steps" class = "slick-initialized slick-slider">

    <!-- Step slides -->
    <div class = "join-club-steps" id = "join-step-gender">
    <!-- Step 1 Content: Pick Gender -->
    <h2>Step 1: Pick Gender</h2>
    <label class = "gender_male"><input class = "hide_radio" type = "radio" name = "gender" value = "male"> Male</label>
    <label class = "gender_female"><input class = "hide_radio" type = "radio" name = "gender" value = "female"> Female</label>
    </div>
    <div class = "join-club-steps" id = "join-step-size">
    <!-- Step 2 Content: Pick Size -->
    <h2>Step 2: Pick Size</h2>
    <label class = "size_club"><input class = "hide_radio" type = "radio" name = "size" value = "s"> S</label>
    <label class = "size_club"><input class = "hide_radio" type = "radio" name = "size" value = "m"> M</label>
    <label class = "size_club"><input class = "hide_radio" type = "radio" name = "size" value = "l"> L</label>
    <label class = "size_club"><input class = "hide_radio" type = "radio" name = "size" value = "xl"> XL</label>
    <label class = "size_club"><input class = "hide_radio" type = "radio" name = "size" value = "2xl"> 2XL</label>
    </div>

    <div class = "join-club-steps" id = "join-step-product">
    <!-- Step 3 Content: Pick Product -->
    <h2>Step 3: Pick Product</h2>
    <label class = "product_club"><input class = "hide_radio" type = "radio" name = "product" value = "SPIKE SHIRT BOX"> SPIKE SHIRT BOX<br><span id = "product_detail_club">Receive One Shirt Each Month</span></label>
    <label class = "product_club"><input class = "hide_radio" type = "radio" name = "product" value = "SPIKE HAT BOX"> SPIKE HAT BOX<br><span id = "product_detail_club">Receive One Hat Each Month</span></label>
    <label class = "product_club"><input class = "hide_radio" type = "radio" name = "product" value = "TROPHY COMBO BOX"> TROPHY COMBO BOX<br><span id = "product_detail_club">2 Items - Receive One Shirt AND One Hat Each Month </span></label>
    <label class = "product_club"><input class = "hide_radio" type = "radio" name = "product" value = "DEAL BOX"> DEAL BOX<br><span id = "product_detail_club">Hat OR Shirt from PAST Designs to Save You Money Each Month Alternates Between Shirt and Hat</span></label>
    </div>

    <div class = "join-club-steps" id = "join-step-billing">
    <!-- Step 4 Content: Pick Billing Frequency -->
    <h2>Step 4: Pick Billing Frequency</h2>
    <label class = "billing_club"><input class = "hide_radio" type = "radio" name = "billing" value = "1st Month"> 1st Month $1.00<br><span id = "product_detail_club">THEN $28 MONTHLY 6 MONTH MIN AGREEMENT</span></label>
    <label class = "feq_club"><input class = "hide_radio" type = "radio" name = "billing" value = "Monthly"> Monthly<br><span id = "feq_detail_club">$28.00 every month, no contract</span></label>
    <label class = "feq_club"><input class = "hide_radio" type = "radio" name = "billing" value = "3 Months"> 3 Months<br><span id = "feq_detail_club">$25.50/SHIRT $75.60 ONE TIME </span></label>
    <label class = "feq_club"><input class = "hide_radio" type = "radio" name = "billing" value = "6 Months"> 6 Months<br><span id = "feq_detail_club">$23.80/SHIRT $142.80 ONE TIME</span></label>
    <label class = "feq_club"><input class = "hide_radio" type = "radio" name = "billing" value = "12 Months"> 12 Months<br><span id = "feq_detail_club">$22.40/SHIRT $268.80 ONE TIME</span></label>
    </div>

    <!-- Final slide to show user selections -->
    <div class = "join-club-steps final-slide">
    <h2>Your Selections</h2>
    <p>Gender: <span id = "selectedGender"></span></p>
    <p>Size: <span id = "selectedSize"></span></p>
    <p>Product: <span id = "selectedProduct"></span></p>
    <p>Billing Frequency: <span id = "selectedBilling"></span></p>
    <a href = "" id = "product-link" target = "_blank"><button id = "join-now-btn">Join Now</button></a>
    <button id = "reset-btn">Reset</button>
    </div>
</div>
<div id = "join-club-progress-bar">
    <ul>
    <li>
        <div class = "circle" data-step = "1">1</div>
    </li>
    <li>
        <div class = "circle" data-step = "2">2</div>
    </li>
    <li>
        <div class = "circle" data-step = "3">3</div>
    </li>
    <li>
        <div class = "circle" data-step = "4">4</div>
    </li>
    </ul>
</div>
</div>

Заранее спасибо!

Я проверил, что идентификаторы, используемые для обновления окончательного содержимого слайда (selectedGender, selectedSize, selectedProduct, selectedBilling), соответствуют идентификаторам, указанным в моем HTML.

Я проверил, что привязка событий для изменений переключателей работает правильно и что событие изменения запускается, как ожидалось.

Форма перейдет на финальный слайд, но не будет отображать введенные пользователем данные и ссылку на продукт, которому она соответствует.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам нужно немного настроить nextStep в обработчике событий change для ваших переключателей.

Вместо

  $('input[type = "radio"]').on("change", function () {
    var currentStep = $(this).closest(".join-club-steps");
    var nextStep = currentStep.next(".join-club-steps");

    // Show final slide if on the last step and valid
    if (nextStep.length === 0 && isStepValid(currentStep)) {
      showFinalSlide();
    } else {
      navigateSteps(this, "next");
    }
  });

сделай это

  $('input[type = "radio"]').on("change", function () {
    var currentStep = $(this).closest(".join-club-steps");
    var nextStep = currentStep.next(".join-club-steps:not(.final-slide)"); // <--- this was added

    // Show final slide if on the last step and valid
    if (nextStep.length === 0 && isStepValid(currentStep)) {
      showFinalSlide();
    } else {
      navigateSteps(this, "next");
    }
  });

Слайд :not(.final-slide) необходим, потому что без него nextStep подбирает элемент с классом .final-slide. Причина такого выбора в том, что у него также есть класс .join-club-steps.

Если вы не уверены в моем объяснении, сделайте следующее. Первым делом в коде Javascript перед $(document).ready(...) добавьте что-то вроде var tmp;. Затем внутри $('input[type = "radio"]').on("change", function () {...}); добавьте tmp = $(this);. Это установит переменную tmp в значение, проверенное на последнем шаге, и затем вы сможете вручную, через консоль браузера, сделать что-то вроде

console.info(tmp);
console.info(tmp.closest('.join-club-steps'));
console.info(tmp.next('.join-club-steps'));

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

Кроме того, вам, вероятно, следует решить проблему CLS, которая возникает при изменении шагов.


РЕДАКТИРОВАТЬ

Как предложил Марк Шультайс в комментариях, поскольку currentStep и nextStep не будут изменены в течение всего времени существования контекста, в котором они использовались (внутренние переменные внутри анонимной функции), вместо использования

$('input[type = "radio"]').on("change", function () {
    var currentStep = $(this).closest(".join-club-steps");
    var nextStep = currentStep.next(".join-club-steps:not(.final-slide)");

    // rest of your code for this event handler
});

вы можете изменить его, чтобы он выглядел так:

$('input[type = "radio"]').on("change", function () {
    const currentStep = $(this).closest(".join-club-steps");
    const nextStep = currentStep.next(".join-club-steps:not(.final-slide)");

    // rest of your code for this event handler
});

Это также можно сделать и в других частях кода, где переменные объявляются внутри ваших функций (isStepValid, showFinalSlide, navigateSteps).

Это не является абсолютной необходимостью — в данном случае ваш код будет работать как с var, так и с const. Но желательно внести это изменение — см. следующий ТАК-ответ, чтобы лучше понять, почему.

рассмотрите возможность предложения таких объявлений, как const currentStep, поскольку они не изменятся.

Mark Schultheiss 24.02.2024 00:12

Другие вопросы по теме