JavaScript 練習 - 計算機

Demo

Introduction 介紹

這是一個很經典的基礎 JavaScript 練習題,一開始把題目想得太複雜,但參考網上的作法後,了解到如何運用基礎的 JavaScript 語法做出一個基本功能的計算機。這個練習會用到:

  • 變數
  • if-else 條件判斷
  • includes() 方法
  • matches() 方法
  • dataset 自定義資料屬性
  • Event deligation 事件委派

基本 HTML 結構

基本的 HTML 結構如下,可以看到輸入欄位、運算符號及數字鍵,其中運算符號上面具備 data-action 屬性以便點擊時取得相應功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<div class="container">
<div class="calculator">
<div class="calculator__display">0</div>

<div class="calculator__keys">
<button class="key--operator" data-action="add">+</button>
<button class="key--operator" data-action="subtract">-</button>
<button class="key--operator" data-action="multiply">&times;</button>
<button class="key--operator" data-action="divide">÷</button>
<button>7</button>
<button>8</button>
<button>9</button>
<button>4</button>
<button>5</button>
<button>6</button>
<button>1</button>
<button>2</button>
<button>3</button>
<button>0</button>
<button data-action="decimal">.</button>
<button data-action="clear">AC</button>
<button class="key--equal" data-action="calculate">=</button>
</div>
</div>
</div>

基礎功能

使用事件委派監聽

監聽所有點擊事件,在此使用事件委派監聽,因為所有按鍵都是 keys 的子層,並且使用 matches() 確定按下的鍵的類型。如果按下的鍵屬性是 button,那就指向觸發事件的 DOM 物件。

1
2
3
4
5
6
7
const calculator = document.querySelector(".calculator");
const keys = document.querySelector(".calculator__keys");
const action = key.dataset.action;
keys.addEventListener("click", (e) => {
if(e.target.matches('button')){
const key = e.target;
}

並且利用 data-action 與判斷式,判斷點擊目標的自定義資料屬性。一個簡單的計算機可能發生以下幾種狀況:

  • 數字鍵 (0-9)
  • 運算符 an operator key (+, -, ×, ÷)
  • 小數點
  • 等於
  • 清除
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
const key = e.target;
const action = key.dataset.action;

if (!action) {
//如果點擊目標不是任何運算動作,就是數字
}
if (
action === "add" ||
action === "subtract" ||
action === "multiply" ||
action === "divide"
) {
//如果點擊鍵是+-*/
}

if (action === "decimal") {
//如果點擊鍵是小數點
}

if (action === "clear") {
//如果點擊鍵是清除
}

if (action === "calculate") {
//如果點擊鍵是等於
}

取得輸入值並顯示在計算機

計算機都會有一個開機預設的 0,如果按下任何一個數字鍵,就會取代目前銀幕上的 0。如果銀幕上現在是非 0 的其他數字,按下第二個數字鍵,就會附加在目前顯示的數字尾巴。所以這裡需要獲得 2 項資訊:

  • 目前點擊數字
  • 目前銀幕顯示數字

透過 textContent 屬性取得上面兩項資訊的值

1
2
3
4
5
6
7
8
9
10
const display = document.querySelector(".calculator__display"); // 取得計算機銀幕欄位
keys.addEventListener("click", (e) => {
if (e.target.matches("button")) {
const key = e.target;
const action = key.dataset.action;
const keyContent = key.textContent; //取得點擊鍵的值
const displayedNum = display.textContent; //取得銀幕顯示值
// ...
}
});

假如銀幕現在顯示 0,取代現在顯示的 0;不是 0,例如 1,附加點擊的第二個按鍵在 1 後面例如 13

1
2
3
4
5
6
7
if (!action) {
if (displayedNum === "0") {
display.textConten = keyContent;
} else {
display.textConten = displayedNum + keyContent;
}
}

小數點

  • 使用 includes() 檢查字串有沒有小數點,如果沒有小數點,而且前一個點擊事件不是運算符,例如 11,那就加上小數點
  • 如果前一個點擊事件是等號或者運算符事件,點擊小數點就會顯示 0.
1
2
3
4
5
6
7
8
9
10
11
if (action === "decimal") {
if (!displayedNum.includes(".") && previousKeyType !== "operator") {
display.textContent = displayedNum + ".";
} else if (
previousKeyType === "operator" ||
previousKeyType === "calculate"
) {
display.textContent = "0.";
}
calculator.dataset.previousKeyType = "decimal";
}

運算符號事件:新增第二個運算數字

一個兩個數字的運算,例如 1 + 3 會有三個資料需儲存

  • 第一個數字
  • 運算符號
  • 第二個數字

在點擊運算符號的時候,第一個數字會被儲存,第二個數字會取代第一個數字而顯示在銀幕上。所以在點擊運算符號的時候,使用 dataset 儲存第一個數字、目前的點擊事件類型、運算符號號

1
2
3
4
5
6
7
8
9
10
if (
action === "add" ||
action === "subtract" ||
action === "multiply" ||
action === "divide"
) {
calculator.dataset.firstValue = displayedNum; //儲存第一個值
calculator.dataset.previousKeyType = "operator"; //儲存點擊事件類型
calculator.dataset.operator = action; //儲存運算符號
}

等號事件

按下等號的時候,會運用到已經用 dataset 儲存的第一個值、儲存的運算符號、銀幕目前顯示的值。而且按下運算符號後,需把運算結果更新成下一個算式的的第一個值。
例如 5-1 = 4 , 下一個算式的第一個數字就是 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
if (action === "calculate") {
const operator = calculator.dataset.operator;
let firstValue = calculator.dataset.firstValue;
let secondValue = displayedNum;

if (firstValue) {
if (previousKeyType === "calculate") {
firstValue = displayedNum;
secondValue = calculate.dataset.modeValue;
}
display.textContent = calculate(firstValue, operator, secondValue);
}
calculator.dataset.modeValue = secondValue;

calculator.dataset.previousKeyType = "calculate";
}

運算符號事件優化

在運算符號事件發生的時候,如果 按下 8+3+ 就會出現等同於按下等號的狀況。第一個數字已經被儲存,第二個數字現在是銀幕上顯示的數字,所以邏輯跟按下等號一樣

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const operator = calculator.dataset.operator;
let firstValue = calculator.dataset.firstValue;
let secondValue = displayedNum;
if (
firstValue &&
operator &&
previousKeyType !== "operator" &&
previousKeyType !== "calculate"
) {
let calcValue = calculate(firstValue, operator, secondValue);
calculator.dataset.firstValue = calcValue;
display.textContent = calcValue;
} else {
calculator.dataset.firstValue = displayedNum;
}

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 CYC'S BLOG All Rights Reserved.

UV : | PV :