iT邦幫忙

2022 iThome 鐵人賽

DAY 25
0


今天要來做的是小測驗裝置 (ˉ▽ ̄~)


超白話畫面和功能拆解

  • 畫面上每個題目皆為單選題,每一頁只顯示一個測驗
  • 選好答案,,按下submit按鈕,就會自動跳到下一題目
  • 沒有選答案,按下submit無效
  • 最後一頁會顯示你答對幾題,按下Ssubmit會重新導回第一頁

運用知識點羅列

  • CSS
知識點 使用說明
background-image 設置linear-gradient() 線性漸層
  • JS
知識點 使用說明
forEach( ) 遍歷每個題目的答案
addEventListener 為送出按鈕加上
innertext 把題目渲染到畫面上
innerHTML 把最後一頁(答對了幾題)渲染到畫面上
location.reload( ) 刷新頁面

流程講解

  • HTML
    先準備四個題目,每題都是單選題
    <div class="container" id="container">
        <div class="quiz-header">
            <h2 id="question">Question Test</h2>
            <ul>
                <!-- 題目一 -->
                <li>
                    <input type="radio" name="answer" id="a" class="answer">
                    <label for="a" id="a-text"></label>
                </li>
                <!-- 題目二-->
                <li>
                    <input type="radio" name="answer" id="b" class="answer">
                    <label for="b" id="b-text"></label>
                </li>
                <!-- 題目三 -->
                <li>
                    <input type="radio" name="answer" id="c" class="answer">
                    <label for="c" id="c-text"></label>
                </li>
                <!-- 題目四 -->
                <li>
                    <input type="radio" name="answer" id="d" class="answer">
                    <label for="d" id="d-text"></label>
                </li>
            </ul>
        </div>

    </div>
    <button id="submit">Submit</button>
    </div>

  • CSS
    大局配置
* {
  box-sizing: border-box;
}

body {
  background-color: #bcdf49;
  background-image: linear-gradient(315deg, #bcdf49, #d9e4b5);
  margin: 0;
  padding: 0;
  display: flex; /*讓內容在viewport的中間*/
  justify-content: center;
  align-items: center;
  height: 100vh;
  overflow: hidden;
}

外部容器

.container {
  background-color: #fff;
  border-radius: 10px;
  box-shadow: 0 0 10px rgb(100, 100, 100);
  width: 600px;
  overflow: hidden;
}

測驗相關

.quiz-header {
  padding: 4rem;
}
h2 {
  padding: 1rem;
  text-align: center;
  margin: 0;
}
.quiz-header ul {
  list-style-type: none;
  padding: 0;
}
.quiz-header ul li {
  font-size: 18px;
  margin: 18px 0;
}
.quiz-header ul li label {
  cursor: pointer;
}

提交按鈕

button {
  background-color: rgba(136, 136, 136, 0.8);
  border: 0;
  color: white;
  display: block;
  width: 100%;
  cursor: pointer;
  font-size: 18px;
  padding: 5px 10px;
}
button:hover {
  background-color: rgb(136, 136, 136);
}
button:focus {
  outline: none;
  background-color: rgb(99, 99, 99);
}

以上都設定好呈現如下,背景有漸層效果,若想了解更多漸層相關的設置可以點這
https://ithelp.ithome.com.tw/upload/images/20221001/20149362mng2ZOzm7A.png

  • JS
    變數設置
const container = document.getElementById("container");
const answerEl = document.querySelectorAll(".answer");
const questionEl = document.getElementById("question");
const a_text = document.getElementById("a-text");
const b_text = document.getElementById("b-text");
const c_text = document.getElementById("c-text");
const d_text = document.getElementById("d-text");
const submitBtn = document.getElementById("submit");
let currentQuiz = 0; //當前測驗
let score = 0;

測驗題目
(共有四題,因篇幅關係只放一題)
建立一個陣列裡包物件,物件的內容無非就是跟測驗有關的資訊(題目、ABCD選項、答案)這裡沒有要去串接外部API

let quizs = [
  {
    question: "正方形是有角的圖形,這個圖形沒有角,所以,",
    A: "這個圖形是個圓。",
    B: "這個圖形是橢圓",
    C: "這個圖形不是正方形。",
    D: "無確切的結論。",
    correct: "C",
  },
 //後面省略
];

載入測驗的fn

loadQuiz();
function loadQuiz() {
  deselectAnswer();  //清除選取的選項

  let currentQuizData = quizs[currentQuiz];
  
  questionEl.innerText = currentQuizData.question;
  a_text.innerText = currentQuizData.A;
  b_text.innerText = currentQuizData.B;
  c_text.innerText = currentQuizData.C;
  d_text.innerText = currentQuizData.D;
}

上頭是要把測驗的標題和選項內容從陣列物件中取出,陣列使用[ ]、物件使用.(點)

設定好後,呈現如下,確實可以看到題目了
https://ithelp.ithome.com.tw/upload/images/20221001/201493624XFDxXC55f.png


deselectAnswer();

function deselectAnswer() {
  answerEls.forEach((answerEl) => {
    answerEl.checked = false;
  });
}

檢查哪一個選項被選中

function getSelected() {
  let answer;
  answerEls.forEach((answerEl) => {
    if (answerEl.checked) {
      answer = answerEl.id;
    }
  });
  return answer;
}

按鈕

submitBtn.addEventListener("click", () => {
  let answer = getSelected(); //getSelected()被使用者選中的那個選項
   console.log(answer);  //看底下的圖
});

以上都設置好,呈現如下,選第一個選項,按下按鈕會出現a,第二個會出現b,以此類推...
那為什麼需要要知道這些呢?

因為當我們可以抓取到使用者選了哪個選項後,就可以來比對答案跟它究竟是否一樣

接下來,底下的程式碼使用"雙層判斷",先判斷answer是否為空,不為空代表使用者有選了某個選項,才能進到下一步,與答案進行比對,另外,因這部分是在按鈕按下的那瞬間要執行,所以接續著把剛剛按鈕的部分寫得更完整一點

submitBtn.addEventListener("click", () => {
  let answer = getSelected(); //找出被使用者選中的那個選項
  console.log(answer);

  if (answer) {
    if (answer === quizData[currentQuiz].correct) {
      score++;
    }

    currentQuiz++; //答對了進到下一題

    if (currentQuiz < quizData.length) {
      loadQuiz();
    } else {
      container.innerHTML = `
      <h2>恭喜你完成此份測驗,共答對:${score} / ${quizData.length} 題</h2>
      
      <button onclick="location.reload()">Reload</button>
      `;
    }
  }
});

來講解一下上面有用到的知識點

location.reload()

The location.reload() method reloads the current URL, like the Refresh button.

擷取至MDN

這個方法用於刷新頁面、按鈕,裏頭不須傳入任何參數,location.reload() 的全貌是 window.location.reload( ) ,window.location 對象可用於獲取當前頁面地址 (URL) 並將瀏覽器重定向到新頁面,不過一般window可以省略不寫

語法:location.reload()

附上codepen連結 https://codepen.io/hangineer/pen/BaxxQay (可以點進來玩玩看喔^^)
若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉


補充

1.What is the Difference Between textContents, innerText, and innerHtml? (英文)
2. innerText 與 textContent的差異
3.Javascript 頁面跳轉、刷新、重定向的幾種方式


參考資料

50 Projects In 50 Days - HTML, CSS & JavaScript
測驗題目參考


上一篇
Day 24 Side Project : Live User Filter 動態篩選器
下一篇
Day 26 Side Project : Testimonial Box Switcher 人物介紹(仿限時動態)
系列文
在30天利用HTML & CSS & JavaScript完成Side Project實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
112182ssss
iT邦新手 4 級 ‧ 2023-11-16 21:34:28

請問為何我的答案跟正確答案相同,但是結果是零分/images/emoticon/emoticon02.gif

hannnahTW iT邦新手 3 級 ‧ 2023-11-16 22:31:28 檢舉

有囉!你再試試看

我要留言

立即登入留言