拋去廢話,直接開擼本文為學習 How to build a calculator—part 1的記錄。建議看原文!
先搭個頁面結構
看上圖,這個計算器分兩個主要部分:螢幕、鍵盤:
<div class="calculator">
<div class="calculator__display">0</div>
<div class="calculator__keys">
</div>
</div>
複製程式碼
鍵盤部分有+
、-
、*
、/
等按鍵:
<div class="calculator__keys">
<button class="keys--operator" data-action="add">+</button>
<button class="keys--operator" data-action="sub">-</button>
<button class="keys--operator" data-action="multi">*</button>
<button class="keys--operator" data-action="div">/</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>
複製程式碼
整個頁面就這麼多東西了~
再加點樣式
計算器放在整個網頁的中間好看點
body{
height: 100vh;
background-image: linear-gradient(236deg, #74ebd5, #acb6e5);
display: flex;
justify-content: center;
align-items: center;
}
複製程式碼
再來個圓角,美觀
.calculator {
border-radius: 12px;
box-shadow: 0 0 40px 0 rgba(0, 0, 0, 0.15);
overflow: hidden;
}
複製程式碼
顯示器的背景偏黑色,數字是白色的。
.calculator__display {
background-color: #222;
color: #fff;
font-size: 2em;
padding: 0.5em 0.75em;
text-align: right;
}
複製程式碼
按鍵用 grid
佈局,輕鬆搞定
.calculator__keys {
background-color: #999;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 1px;
}
.calculator__keys>* {
background-color: #fff;
padding: 0.5em 1.25em;
position: relative;
text-align: center;
}
.keys--operator {
background-color: #eee;
}
.key--equal {
background-image: linear-gradient(to bottom, #fe886a, #ff7033);
grid-column: -2;
grid-row: 2/span 4;
}
複製程式碼
按鍵在點選的時候應該有按鍵效果,運算鍵被按下後也需要有提示
.calculator__keys>*:active::before,
.calculator__keys>.is-depressed::before {
content: "";
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.2);
box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.5) inset;
position: absolute;
}
複製程式碼
整個頁面就算完成了
開始處理運算邏輯
既然是計算器,肯定要監聽點選事件並且判斷點選的是哪一個按鍵。
const calculator = document.querySelector('.calculator');
const display = calculator.querySelector('.calculator__display');
const keys = calculator.querySelector('.calculator__keys');
keys.addEventListener('click',e=>{
if(e.target.matches('button')){
const key = e.target;
const action = key.dataset.action;
...
}
})
複製程式碼
按鍵從功能上分五種:數字鍵、運算鍵、小數點、清除鍵、求值鍵。其中運算鍵、小數點、清除鍵、求值鍵都有data-action
屬性。沒有data-action
屬性的就是數字鍵了。通過這個屬性判斷被點選的是哪種按鍵。
const action = key.dataset.action;
if(!action){
console.log('number');
}else if(action === 'add' || action === 'sub' || action === 'multi' || action === 'div'){
console.log('operator');
}else if(action === 'decimal'){
console.log('decimal');
}else if(action === 'clear'){
console.log('clear');
}else if(action==='calculate'){
console.log('calculate');
}
複製程式碼
一般情況
點選數字鍵:
點選數字鍵分兩種情況:
- 顯示器顯示為'0'時按數字鍵,顯示器上顯示的數字應該變成所按的數字
- 顯示器不為'0'時按數字鍵,顯示器上顯示的數字應該是已顯示的數字最後一位加上所按的數字
if(!action){
if(display.textContent ==='0'){
display.textContent = key.textContent;
}else {
display.textContent+=key.textContent;
}
}
複製程式碼
點選運算鍵
點選運算鍵後,應該有該鍵被按下的狀態提示
if(action === 'add' || action === 'sub' || action === 'multi' || action === 'div'){
key.classList.add('is-depressed');
}
複製程式碼
之後再點選其餘按鍵,被按下狀態提示應該取消
const action = key.dataset.action;
Array.from(key.parentNode.children).forEach(k => k.classList.remove('is-depressed'));
複製程式碼
點選小數點
點選小數點後,小數點應該加在顯示器顯示的數字後面
if(action==='decimal'){
display.textContent +='.';
}
複製程式碼
但是,假如顯示器上已經有小數點了,不應該響應這次點選,所以修改下程式碼
if(action==='decimal'){
if(!display.textContext.includes('.')){
display.textContext+='.'
}
}
複製程式碼
點選清除鍵
AC 鍵是將計算器所有狀態重置。後面會加 CE 鍵。暫時就是重置顯示器:
if(action==='clear'){
display.textContent='0';
}
複製程式碼
點選計算鍵
計算鍵簡單,就是算下加減乘除。寫個函式好了:
function calculate(firstValue,operator,secondValue){
switch(operator){
case 'add':
return firstValue+secondValue;
case "sub":
return firstValue-secondValue;
case "multi":
return firstValue*secondValue;
case "div":
return firstValue/secondValue;
default:
return "NaN";
}
}
if(action==='calculate'){
display.textContent = calculate(firstValue,operator,secondValue);
}
複製程式碼
但是,firstValue
,operator
,secondValue
從何而來?
secondValue
就是當前螢幕上的內容,
secondValue = display.textContent;
複製程式碼
firstValue
、operator
在點選計算鍵時還存在,趁機將其儲存起來
if(action === 'add' || action === 'sub' || action === 'multi' || action === 'div'){
key.classList.add('is-depressed');
calculator.dataset.operator = action;
calculator.dataset.firstValue = display.textContent;
}
複製程式碼
修改一下點選計算鍵的程式碼:
const firstValue = calculator.dataset.firstValue;
const operator = calculator.dataset.operator;
const secondValue = display.textContent;
display.textContent = calculate(firstValue,operator,secondValue);
複製程式碼
新增清除按鈕的重置:
display.textContent='0';
calculator.dataset.firstValue ='';
calculator.dataset.operator = '';
複製程式碼
至此,一個未處理特殊情況,但功能還算完備的計算器就完成了。剩下的工作就是處理各種組合輸入,儘量讓計算器沒有 BUG。