Egyszerű számológép CSS Grid alkalmazásával

Mi a cél?

Egy egyszerű számológép készítése, melynél több műveleti operátort is megadhatunk egymás után, ekkor viszont ERROR-t kapunk és a többféle művelet összefűzése nem a precedencia szabályai szerint értékelődik ki, hanem egyszerűen balról-jobbra.

DEMO (a képre kattintva indul)

Egyszerű számológép

A HTML template

A HTML váz most tényleg csak egy váz, a számok celláit ugyanazon szám értékű id-ekkel jelöljük.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Számológép</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="calculator"> <div class="display"></div> <div class="cell plus firstLine" id="+">+</div> <div class="cell minus firstLine" id="-">-</div> <div class="cell multiply firstLine" id="*">x</div> <div class="cell divide firstLine" id="/">÷</div> <div class="cell number" id="7">7</div> <div class="cell number" id="8">8</div> <div class="cell number" id="9">9</div> <div class="equal">=</div> <div class="cell number" id="4">4</div> <div class="cell number" id="5">5</div> <div class="cell number" id="6">6</div> <div class="cell number" id="1">1</div> <div class="cell number" id="2">2</div> <div class="cell number" id="3">3</div> <div class="cell number" id="0">0</div> <div class="cell dot">.</div> <div class="cell clear">C</div> </div> <script src="main.js"></script> </body> </html>

A CSS stílus

A számológép layout-jának szabálytalan elem elhelyezkedése a CSS Grid után kiált, de gyakorlásképpen ugyanezen design a github repoban CSS Flexbox használatával került megvalósításra.

* { margin: 0; padding: 0; } *, *::before, *::after { box-sizing: inherit; } html { box-sizing: border-box; } body { min-height: 100vh; position: relative; font-family: sans-serif; } .calculator { display: grid; grid-template-columns: auto auto auto auto; border: 1px solid rgba(0,0,0, 0.2); box-shadow: 0 4px 8px rgba(0,0,0, 0.2); gap: .7rem; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 1.5rem; } .display { grid-column: 1 / span 4; border: 1px solid rgba(0,0,0, 0.2); box-shadow: 1px 1px 3px rgba(0,0,0, 0.2); color: rgba(0,0,0, 0.5); height: 5rem; font-size: 2rem; display: flex; justify-content: flex-end; align-items: center; padding-right: .5rem; } .equal { grid-row: 3 / span 4; grid-column-start: 4; font-size: 3rem; display: flex; justify-content: center; align-items: center; background-color: rgb(102, 102, 252); box-shadow: 0 1px 2px rgba(0,0,0, 0.2); color: #fff; cursor: pointer; } .equal:hover { background-color: rgb(15, 15, 221); } .cell { border: 1px solid rgba(0,0,0, 0.2); font-size: 2rem; height: 4rem; width: 7rem; display: flex; justify-content: center; align-items: center; background-color: rgba(0,0,0, 0.03); box-shadow: 0 1px 2px rgba(0,0,0, 0.2); cursor: pointer; color: rgba(0,0,0, 0.5); } .cell:hover { background-color: rgba(0,0,0, 0.2); } .firstLine { background-color: rgba(0,0,0, 0.15); } .firstLine:hover { background-color: rgba(0,0,0, 0.5); color: #fff; }

A Javascript logika

Először felírjuk a használni kívánt DOM elemeket, Nodelist-eket.

const display = document.querySelector('.display'); const numberButtons = document.querySelectorAll('.number'); const clear = document.querySelector('.clear'); const operatorButtons = document.querySelectorAll('.firstLine'); const dot = document.querySelector('.dot'); const equal = document.querySelector('.equal');

Beállítjuk a változók kezdeti értékeit és a kijelzőt 0-val indtjuk.

let result = 0; display.textContent = 0; let numbers = []; let operators = [];

A szám és az operátor gombokra felírjuk az eseményfigyelőket, mely megjeleníti a lenyomott gomb tartalmát a kijelzőn. A NodeList-eket jelen esetben nem muszáj tömbbé alakítani, mert nekik is van beépített forEach() metódusuk. Ha 0 van a kijelzőn, akkor az operátorok nem kerülnek elfogadásra, de ez egyéni, mert így viszont nem lehet 0-val kezdeni a műveletet. Ezért "egyszerű' a számológépünk.

Array.from(numberButtons).forEach(item => { item.addEventListener('click', () => { if (display.textContent.startsWith('0')) display.textContent = ''; display.textContent += item.textContent; }) }); Array.from(operatorButtons).forEach(item => { item.addEventListener('click', () => { if (display.textContent.startsWith('0')) { return false; } display.textContent += item.textContent; }) })

A C gombbal mindent letörlünk és alaphelyzetbe állítunk.

clear.addEventListener('click', () => { display.textContent = 0; result = 0; operators = []; numbers = []; })

Az egyenlőségjel kiértékeli a kijelzőn megjelenő sztringet, mégpedig úgy, hogy külön tömbbe szedi a számokat és az operátorokat és elvégzi a megfelelő műveleteket.

equal.addEventListener('click', () => { handleResult(); display.textContent = result; }) function handleResult() { getNumbersArray(); getOperatorsArray(); operations(); return result; }

A számok és az operátorok külön tömbbökbe szedése hasonló módon történik, mert előbbi esetben a kijelzőn megjelenő szöveget a nem számok mentén, míg utóbbi esetbenn a számok mentén feldaraboljuk és a megfelelő értékeket tömbbe rakjuk.

function getNumbersArray() { let numbersString = []; numbersString = display.textContent.split(/\D+/); numbersString.forEach(item => { if (typeof parseInt(item) === 'number') { numbers.push(parseInt(item)); } }); } function getOperatorsArray() { let operatorsString = []; operatorsString = display.textContent.split(/\d/); operators = operatorsString.filter(item => item !== ''); }

Végül a szám és az operátor tömb megfelelő elemeivel elvégezzük a műveletet, kizárva azt a lehetőséget amikor több operátor van egymás mellett, mert akkor kiugrunk a végrehajtásból és ERROR-t adunk vissza.

function operations() { result = numbers[0]; numbers.shift(); numbers.forEach((item, index) => { handleValidOperators(); if (operators[index] === "+") { result += item } else if (operators[index] === '-') { result -= item } else if (operators[index] === '÷') { result /= item } else if (operators[index] === 'x') { result *= item }; }) } function handleValidOperators() { operators.forEach(item => { if (item.length >= 2) { result = "ERROR"; return false; } }) }