MENU

【Javascript】画面遷移型の診断テストをつくってみた!(複数選択)

診断コンテンツを作成してみた

絶賛、Javascriptを勉強中で、ちょうど案件で診断コンテンツを作成することになりました。
記事でヒットするのは、JQueryのものなどあったのですが、あえてJavascriptで挑戦してみました!

CONTENTS

完成ソース

こちらが、完成したものになります。
今回、診断コンテンツが2種ありそうだったので、設問や結果の文言などは、HTMLに直書きをするようにしました。

もし、診断コンテンツが一つだけになるなら、scriptをまとめてもいいと思います。

See the Pen Untitled by komame (@komame) on CodePen.

ざっくりとした仕組みについて

まず、こちらは画面遷移型の診断コンテンツです。

設問や結果の表示は、HTML側でscriptを記述するような作りにして、設問数や結果の分岐は、連想配列の数に応じるので、使い回しができるようにしました。

選択ボタンには、data属性でそれぞれ数値をもたせ、選択した合計値をもとに、結果が分岐するような作りになっています。

一点、気に入っていない箇所があります。それは、選択した数値の配列を合算を、totalScoreという変数に格納したのですが、こちらの数値をHTML側に記述しているところです!

scirpt側で記述していると、showResultText();で値が渡せなくて、きっと他にやり方があるんだと思うんですが。。

ソースの説明

スタートボタンをクリックしたときの挙動

スタートボタンをクリックしたときの関数をstartQuiz()にまとめています。
currentQuestionIndexは、連想配列を取り出すときに必要で、初期化で0にしておきます。

currentQuestionIndex = 0;
startButton.addEventListener('click', () => {
  startQuiz();
})

function startQuiz() {
  startButton.classList.add('hide')
  resultContainer.classList.add('hide')
  questionContainer.classList.remove('hide')
  showQuestion()
}

スタートボタンをクリックして、設問を表示させる

スタートボタンをクリックしたときに、showQuestion()という関数を実行させます。

設問は、questionElement(id=”question”)の要素に、連想配列のquestionがcurrentQuestionIndexをキーに挿入されます。

選択肢は、answerButtonsElementというid=”answer-buttons”の配下に、ボタンタグを生成し、連想配列のanswersのtext、valueを挿入しています。

valueは、結果を判定するために、それぞれ数値をもたせて、その得点数で最後分岐するようにしたいので、ボタンタグにdata-valueという属性が入るようにしています。

function showQuestion() {
  // 連想配列の値をそれぞれ挿入

  // タイトル
  questionElement.innerText = questions[currentQuestionIndex].question;

  // 設問
  questions[currentQuestionIndex].answers.forEach(answer => {
    // ボタンタグを生成して、設問を挿入
    const button = document.createElement('button')
    button.innerText = answer.text;
    const value = answer.value;
    button.dataset.value = value;
    answerButtonsElement.appendChild(button)

    // 選択肢をクリックをする
    button.addEventListener('click', selectAnswer)
  })
}

questionとanswerの連想配列は、HTML側に記述しています。

選択ボタンをクリックしたときの挙動

そして、選択したボタンをクリックすると、selectAnswerという関数が実行されます。

選択したボタンのdata-value属性の数値を取得して、scoreArrayという配列に格納します。

ここで、currentQuestionIndex++と配列の数を加算して、次の問題に切り替わるようにしています。
また、resetState()answerButtonsElement.appendChild(button)で、挿入したボタンを全削除しています。

if分岐で、最後の設問をクリックしたら、showResult()という関数に移ります。

// 回答の選択
function selectAnswer(e) {
  const selectedButton = e.target;
  // 選択したボタンのvalueを取得
  const scoreData = parseInt(selectedButton.dataset.value);
  // 配列に格納
  scoreArray.push(scoreData);

  if (currentQuestionIndex < questions.length - 1) {
    resetState()
    currentQuestionIndex++
    // console.log(currentQuestionIndex);
    // console.log(scoreArray)
    // nextButton.classList.remove('hide');
    showQuestion()
  } else {
    showResult();
  }
}

function resetState() {
  // https://into-the-program.com/removechild/
  // これで子要素をすべて削除
  while (answerButtonsElement.firstChild) {
    answerButtonsElement.removeChild(answerButtonsElement.firstChild)
  }
}

resetState()で、挿入したボタンを削除する

子要素の削除の仕方がよくわからなかったのですが、下記を参考にしました。

Into the Program
【JavaScript】特定の子要素(子ノード)を削除する【removeChild】 本記事では、JavaScriptで要素内に存在する特定の子要素を削除する方法のご紹介しています。 上記の疑問にお答えします。 では、解説していきます。 removeChildとは remov...

結果を表示する

設問のブロックをhideというクラスを付与して、非表示にし、
代わりに、resultContainerの要素のhideクラスを削除して、表示させます。

showResultText()の関数は、HTML側に記述していますが、内容は下記のコメントアウトしている内容になります。

今回、診断コンテンツが2パターンある予定だったので、文言や結果の箇所だけページ固有とさせたかったため、HTML側で記述させるようにしました。

結果の文言は、連想配列から呼び出すようにしていますが、result.textの箇所にそのまま書いてもいいですね

// 結果の表示
function showResult() {

  console.log(scoreArray)

  questionContainer.classList.add('hide');
  resultContainer.classList.remove('hide');

  // 下記のコメントアウトの部分をshowResuktText()として、それぞれのページで記述する
  // 配列の数値を合算。
  // const totalScore = scoreArray.reduce(function (sum, currentValue) {
  //   return sum + parseInt(currentValue);
  // }, 0);
  // for (let i = 0; i < results.length; i++) {
  //   const result = results[i];
  //   if (totalScore <= 3 && i === 0) {
  //     scoreElement.innerText = result.text + totalScore;
  //     break;
  //   } else if (totalScore < 6 && i === 1) {
  //     scoreElement.innerText = result.text + totalScore;
  //     break;
  //   } else if (i === 2) {
  //     scoreElement.innerText = result.text + totalScore;
  //     break;
  //   }
  // }

  // showResultTextのfunctionを、それぞれのhtmlの箇所で記述をする。
  showResultText();
}

結果の分岐を変更したい場合は、if (totalScore <= 3 && i === 0) 以降の内容を変更してください。

もう一度診断するボタンをクリックの挙動

もう一度診断するボタンをクリックすると、currentQuestionIndex = 0;で初期化をさせ、scoreArray = [];で配列の中身を空にします。


// もう一度診断するのボタンをクリック
restartButton.addEventListener('click', () => {
  resultContainer.classList.add('hide')
  startButton.classList.remove('hide')
  currentQuestionIndex = 0;
  scoreArray = [];
  resetState()
})

最後に

途中、配列の格納の仕方やループの回し方などがとても混乱しましたが、なんとか作成できました。

診断コンテンツによっては、次へや戻るボタンがあるものもあるので、それが必要になったら、また複雑になりそうだ。。。

診断コンテンツを作成してみた

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
CONTENTS