iT邦幫忙

2021 iThome 鐵人賽

DAY 29
1
Modern Web

舌尖上的JS系列 第 29

D29 - 走!去瀏覽器自己刻表單選 pizza 口味

前言

自己設計 pizza 材料表單!

認識 html input 標籤

input 可以用在表單輸入上,而內建的種類有很~多種,像是預設的文字輸入或是數字輸入、顏色點選甚至是日期視窗等...
MDN input type,今天要來玩的是 input type='radio',稱為單選按鈕,讓使用者可以點選。

今天就設計一張 pizza 標單讓客人選自己想要的配料!

請問您要什麼配料?

基本的 html 架構設定,在 form 表單下放置 label + input 作為選填項目。

html 基本設定

<form id="first-form">
    <p>How would you like your pizza?</p>
    <fieldset class="sauces option">
        <legend>Sauce:</legend>

        <label for="pesto">
            <input type="radio" name="sauce" id="pesto" value="pesto" />
            <span class="checkmark">pesto</span>
    </lable>
    </fieldset>
    ....
</form>

重點:

  • input 包在 label 內可以增加點擊範圍,或是用 label for='input 的 id 名稱' 來綁定同一組的 inputlabel

  • 相同 name 屬性名稱的input 是單選效果,name 名稱不同變為多選 -> 套用在第二種 ingredient 選擇上。

  • inputvalue 屬性設置跟材料稱呼一樣。

先刻出以下畫面:

設定 JavaScript

需要監聽的動作:

  1. 點選時取得材料名稱,右框框展示對應圖片。
  2. 點選提交時改變框框畫面。

第一步:監聽 change Event

radio typeinput 被點選狀態變為 checked 時,change event 可以偵測的這個變化,啟動相應的動作。
利用這個事件,偵測滑鼠點選到哪一個材料,右邊框框 background-image 改為該材料圖片。

// 先選好需要的元素
let get = (tag) => document.querySelector(tag); 
let display = get('.displayImg'); // 右邊展示框

// 直接對 document 綁定 change event
document.addEventListener('change', function (event){
// event.target 會是點選的該材料標籤,取該節點的 value 屬性
let componentImg = event.target.value; // 將點選的 材料 value 存入變數中

// 改變右框框背景圖片為點選的材料
display.style.backgroundImage = `var(--${componentImg})`;
});

綁定 document 的 change event,每次偵測到有框框被點擊時,event.target 會指向該 input,在每個 input 上都有設定屬性 value 值,event.target.value 可以取得設定的材料名稱,放入變數中方便修改背景圖使用。

tips:
利用 css 設定變數的方式,將材料的圖片路徑預先放入 css 變數中,而變數的命名須和屬性 value 值設定一致,就可以依目前印出的 value 值換上該名稱的 css 變數。

第二步:綁定 submit Event

注意:submit event 需綁定在 form 上才有效果,不是 input 也不是 button 唷!因為提交的是整個 form 才對。

formsubmit 事件有預設行為會傳送到 server,但今天的實作不需要傳到後端,因此要用 event.preventDefault() 取消預設行為。

let form = get('#first-form'); // form 表單

// submit 監聽事件綁定在 form 表單上
form.addEventListener('submit', submitOrder);

function submitOrder() {
    event.preventDefault(); //必須取消預設行為
    let options = [...this.elements]; // form 表單下的所有物件存成陣列
    
    // 將背景圖片清空
    display.style.backgroundImage = ''
    
    // 取出點選的元素
    let chosedTarget = options.filter((e) => e.checked);
    
    // 設定 3 秒後印出選擇的材料名稱
    setTimeout(()=>{
          for(let item of chosedTarget){
          display.textContent+= item.value+'';
        }
    },3000)
}

透過展開運算子將 form 表單下的所有元素 this.elements 存入陣列中,不然原本取出的會是 nodeList,使用 filter 取出狀態是 checked = true 的元素,結果要將選擇的材料名稱印在畫面上,用 for...of + display.textContent+= item.value+'' 的方式依序加入右框框的 textContent
內,外面包一層 setTimeout 選擇延遲 3 秒後印出,這樣可以先跑 preparing ... 的動畫效果。

成果

Reference

MDN change event
PJCHENder - CSS Variables
換 input 按鈕 Styling a radio button with only CSS
圖片來源 - freePik
參考: https://codepen.io/gretema/pen/qzwzrG

結語

終~於~快~結~束~了~


上一篇
D28 - 走!去瀏覽器玩轉黑膠唱片 Web Audio API
下一篇
D30 - 舌尖上的 JS 完食!
系列文
舌尖上的JS30

1 則留言

0
Chiahsuan
iT邦新手 5 級 ‧ 2021-10-14 22:02:54

圖片好好看~~

let options = [...this.elements];

這招厲害~學起來/images/emoticon/emoticon12.gif

我要留言

立即登入留言