@hmtwinthdrk

Как сделать прогресс бар для опросника с разными ответами в зависимости от вопроса и его ответа на alpine js?

У меня вопросы имеют два ответа, "да" или "нет", в зависимости от ответа может быть еще один вопрос или сразу же ответ, ответами считаются те объекты у которых choices: [], nextQuestions: [], пустые. Как можно реализовать прогресс бар, чтобы у каждого объекта было по 10% и при ответе он достигал 100?

Код
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
    <link rel="stylesheet" href="./styles/main.css">
    <title>Quiz</title>
</head>
<body>
    <div class="wrapper" x-data="{
        currentQuestionIndex: 0,
        questions: [
          {
            id: 'Question1',
            number: '01',
            text: 'Is your company a manufacturer, importer, or supplier of a product?',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question9', 'Question2']
          },
          {
            id: 'Question2',
            number: '02',
            text: 'Does your company promote or provide services through a website that fall under the BFSG:',
            description: 'Tbanking, courier or postal services, logistics and transport services, internet marketing and related services, electronic insurance services, online booking or payment for any product or service, appointment scheduling, hotel and tour bookings, meeting reservations).',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question4', 'Question3'],
            prevQuestion: 'Question1'
          },
          {
            id: 'Question3',
            number: '03',
            description: 'Currently, your website is not subject to BFSG regulations. However, it\'s possible that the scope of the Accessibility Enhancement Act will expand in the coming years. Additionally, accessibility is becoming a key quality indicator for websites and applications',
            choices: [],
            nextQuestions: [],
          },
          {
            id: 'Question4',
            number: '03',
            text: 'Услуга оказывается только в сегменте B2B?',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question5', 'Question6'],
            prevQuestion: 'Question2'
          },
          {
            id: 'Question5',
            number: '04',
            description: 'The BFSG specifies that accessibility requirements generally apply only to consumer goods and services provided to consumers.',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question6',
            number: '04',
            text: 'Do you provide services in the B2C segment or in a mixed segment, but the company has an officially established status as a micro-enterprise (with fewer than ten employees, maximum annual turnover not exceeding 2 million euros, or annual balance sheet total not exceeding 2 million euros)?',
            choices: ['Yes', 'No'],
            prevQuestion: 'Question4',
            nextQuestions: ['Question7', 'Question8']
          },
          {
            id: 'Question7',
            description: 'According to the Federal Statistical Office, 9.4% of Germany\'s population had severe disabilities as of the end of 2021. Furthermore, 71% of people with disabilities immediately leave a website if it is not accessible.',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question8',
            description: 'Your website or online store falls under the scope of the BFSG, and it must become barrier-free no later than June 28, 2025.',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question9',
            number: '02',
            text: 'Does your product fall under the BFSG',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question10', 'Question11'],
            prevQuestion: 'Question1'
          },
          {
            id: 'Question10',
            description: 'If your product or service falls under the BFSG. ',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question11',
            number: '03',
            text: 'Is your product not covered by the BFSG but sold through an online store?',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question12', 'Question18'],
            prevQuestion: 'Question9'
          },
          {
            id: 'Question12',
            text: ' Selling a product through an online store falls under the category of e-commerce services, which generally falls under the scope of the BFSG. However, certain details need to be clarified.',
            choices: ['Ok'],
            nextQuestions: ['Question13'],
            prevQuestion: 'Question11'
          },
          {
            id: 'Question13',
            number: '04',
            text: 'Does the online store operate exclusively in the B2B segment?',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question14', 'Question15'],
            prevQuestion: 'Question12'
          },
          {
            id: 'Question14',
            description: 'The BFSG specifies that accessibility requirements typically apply only to consumer goods and services provided to consumers. BFSG primarily applies to online stores or websites in the B2C sector. However, in the case of a B2B online store, it must explicitly state on the website that it is a B2B store and does not sell goods to consumers. 3.5',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question15',
            number: '05',
            text: 'Does your online store operate in the B2C segment or in a mixed segment, but the company has an officially established micro-enterprise status (less than ten employees, maximum annual turnover does not exceed 2 million euros or an annual balance of 2 million euros)?',
            choices: ['Yes', 'No'],
            nextQuestions: ['Question16', 'Question17'],
            prevQuestion: 'Question13'
          },
          {
            id: 'Question16',
            description: 'According to the Federal Statistical Office, 9.4% of Germany\' s population had severe disabilities as of the end of 2021. Furthermore, 71% of people with disabilities immediately leave a website if it is not accessible. ',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question17',
            description: 'Your online store falls under the scope of the BFSG, and it must become barrier-free no later than June 28, 2025.',
            choices: [],
            nextQuestions: []
          },
          {
            id: 'Question18',
            number: '04',
            description: 'The product is not covered by the BFSG, you have an information website to present the product. Does the website offer offers and is there an option for online booking or payment?',
            choices: [],
            nextQuestions: []
          },
        ],
        get progress() {
            return ((this.currentQuestionIndex + 1) / this.questions.length) * 100;
        }
    }">
        <section class="quiz">
            <template x-for="(question, index) in questions" :key="index">
                <div x-show="currentQuestionIndex === index" x-bind:id="question.id">
                    <div class="top">
                        <div class="left">
                            <template x-if="question.prevQuestion">
                                <button class="prevBtn" type="button"
                                    @click="currentQuestionIndex = questions.findIndex(q => q.id === question.prevQuestion)">
                                </button>
                            </template>
                        </div>
                        <div class="center">
                            <div class="progress-bar" :style="{ width: progress + '%' }" x-text="progress + '%'"></div>
                        </div>
                        <div class="right"></div>
                    </div>
                    <div class="content">
                        <div class="left" x-text="question.number"></div>
                        <div class="center">
                            <div class="questions">
                                <h1 class="question-text" x-text="question.text"></h1>
                                <p x-text="question.description"></p>
                            </div>
                            <div class="button-container">
                                <template x-for="(choice, choiceIndex) in question.choices" :key="choiceIndex">
                                    <button class="button " type="button" x-bind:class="{
                                            'button-yes': choiceIndex === 0,
                                            'button-no': choiceIndex === 1
                                        }" x-text="choice"
                                        @click="currentQuestionIndex = questions.findIndex(q => q.id === question.nextQuestions[choiceIndex])"></button>
                                </template>
                            </div>
                        </div>
                        <div class="right"></div>
                    </div>
                    <div class="bottom"></div>
                </div>
            </template>
        </section>
    </div>
</body>
</html>
  • Вопрос задан
  • 131 просмотр
Пригласить эксперта
Ответы на вопрос 1
0xD34F
@0xD34F Куратор тега JavaScript
Добавить счётчик полученных ответов, делать ему +/- 1 при переходах к следующему/предыдущему вопросу.

При расчёте прогресса проверять, что текущий вопрос последний (т.е., список возможных следующих вопросов пуст), в зависимости от результата проверки возвращать чего там вам надо - сразу 100 или умножаете счётчик ответов на 10 (кстати, уверены, что больше девяти вопросов задано не будет?).

UPD. Как избавиться от этой ерунды с умножением на 10 - давайте будем вычислять максимальное количество вопросов, которые ещё могут быть заданы. Тогда текущий прогресс будет выражаться отношением количества отвеченных вопросов к сумме отвеченных и оставшихся.

А ещё давайте избавимся от поиска вопросов по их id - для этого следующие/предыдущие вопросы надо хранить в виде индексов вместо id, или вместо массива вопросов сделать объект, где ключами будут id.

Как это может выглядеть:

Рекурсия есть:

getMaxQuestionsLeft(question, depth) {
  return Math.max(
    depth,
    ...question.nextQuestions.map(n => {
      return this.getMaxQuestionsLeft(this.questions[n], depth + 1);
    })
  );
},
get progress() {
  const ac = this.answersCount;
  return Math.floor(ac / (ac + this.getMaxQuestionsLeft(this.question, 0)) * 100);
},

Или, рекурсии нет:

get maxQuestionsLeft() {
  let result = 0;

  for (const stack = [ [ this.question, 0 ] ]; stack.length;) {
    const [ q, d ] = stack.pop();
    result = Math.max(result, d);
    stack.push(...q.nextQuestions.map(n => [ this.questions[n], -~d ]));
  }

  return result;
},
get progress() {
  const { answersCount: ac } = this;
  return ac / (ac + this.maxQuestionsLeft) * 100 | 0;
},
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы