آموزش ساخت ماشین حساب حرفه ای با جاوا اسکریپت

ماشین حساب جاوا اسکریپت – در این مقاله با استفاده از Vanilla Js ( جاوا اسکریپت خالص ) بدون هیچ کتابخانه ای یک ماشین حساب calculator شیک و زیبا بسازیم که علاوه بر دکمه خود امکان استفاده از صفحه کلید را هم داشته باشد .
همچنین در این پروژه از حالت روشن / تاریک هم بهره می بریم برای کاربردی تر شدن ماشین حساب .
دموی برنامه
صفحه index.html
<!DOCTYPE html>
<html lang="fa">
<head>
<meta charset="UTF-8">
<title>Rapidcode.iR - سورس کد</title>
<link rel="stylesheet" href="static/css/main.css">
</head>
<body>
<div class="container">
<a id="introduce" href="https://rapidcode.ir" target="_blank">رپید کد • کتابخانه مجازی برنامه نویسان</a>
<label for="dark-mode">حالت نمایشی :</label>
<select id="dark-mode">
<option value="light">روشن</option>
<option value="dark">تاریک</option>
</select>
<form id="calculator" name="form">
<div class="display">
<input type="text" placeholder="0" id="displayResult" name="displayResult" readonly="readonly"/>
</div>
<div class="buttons">
<div class="row">
<input type="button" class="func-btn wid-2" name="clear" value="C">
<input type="button" class="func-btn wid-2" name="backspace" value="←">
</div>
<div class="row">
<input type="button" class="func-btn" name="b7" value="7">
<input type="button" class="func-btn" name="b8" value="8">
<input type="button" class="func-btn" name="b9" value="9">
<input type="button" class="func-btn" name="addb" value="+">
</div>
<div class="row">
<input type="button" class="func-btn" name="b4" value="4">
<input type="button" class="func-btn" name="b5" value="5">
<input type="button" class="func-btn" name="b6" value="6">
<input type="button" class="func-btn" name="subb" value="-">
</div>
<div class="row">
<input type="button" class="func-btn" name="b1" value="1">
<input type="button" class="func-btn" name="b2" value="2">
<input type="button" class="func-btn" name="b3" value="3">
<input type="button" class="func-btn" name="mulb" value="*">
</div>
<div class="row">
<input type="button" class="func-btn" name="b0" value="0">
<input type="button" class="func-btn" name="potb" value=".">
<input type="button" class="func-btn" name="divb" value="/">
<input type="button" class="func-btn red" name="equal" value="=">
</div>
</div>
</form>
</div>
<script src="static/js/app.js"></script>
</body>
</html>
اسکریپت app.js
// DOM
const darkModeDOM = document.getElementById("dark-mode");
const calculatorDOM = document.getElementById("calculator");
const buttonsDOM = document.getElementsByClassName("func-btn");
const displayResultDOM = document.getElementById('displayResult');
// Property
let displayResultDOMScrollWidth = displayResultDOM.scrollWidth;
let displayResultDOMScrollX = 0;
// set handler
darkModeDOM.onchange = darkModeDOMChangeHandler;
loopThrowDOMS(buttonsDOM, function(element) {
element.onclick = buttonsDOMClick;
});
window.onkeyup = globalKeyPressedHandler;
// handlers
function darkModeDOMChangeHandler(event) {
const thisElementValue = event.target.value;
const darkModeClass = "dark";
loopThrowDOMS(buttonsDOM, function(element) {
if (thisElementValue == "light" && element.classList.contains(darkModeClass))
element.classList.remove(darkModeClass);
else if (thisElementValue == "dark" && !element.classList.contains(darkModeClass))
element.classList.add(darkModeClass);
});
if (thisElementValue == "light" && calculatorDOM.classList.contains(darkModeClass))
calculatorDOM.classList.remove(darkModeClass)
else if (thisElementValue == "dark" && !calculatorDOM.classList.contains(darkModeClass))
calculatorDOM.classList.add(darkModeClass);
}
function globalKeyPressedHandler(event) {
const pressedKey = event.key;
const validKeys = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", ".", "=", "-", "+", "*", "/", "Enter", "Backspace", "Delete"];
const functionalKey = {
"equal": ["Enter", "="],
"backspace": ["Backspace"],
"clear": ["Delete"]
};
var btnName = pressedKey;
loopThrowObject(functionalKey, function(element1, index, mainArray) {
const currentElement = functionalKey[element1];
currentElement.forEach(function(element2) {
if (element2 == pressedKey) {
btnName = element1;
}
});
});
const target = {
value: pressedKey,
name: btnName
}
const thisEvent = {
target: target
}
if (validKeys.includes(pressedKey)) {
buttonsDOMClick(thisEvent);
}
}
function buttonsDOMClick(event) {
const thisElementValue = event.target.value;
const thisElementName = event.target.name;
const specialFunctionalityHandlerNames = ["equal", "clear", "backspace"];
if (specialFunctionalityHandlerNames.includes(thisElementName)) {
switch (thisElementName) {
case 'equal':
try {
equalDOMHandler();
} catch (err) {
alert("خطای ورودی عملیات ریاضی");
}
break;
case 'clear':
try {
clearDOMHandler();
} catch (err) {
alert("خطای ورودی عملیات ریاضی");
}
break;
case 'backspace':
try {
backspaceDOMHandler();
} catch (err) {
alert("خطای ورودی عملیات ریاضی");
}
break;
}
displayResultDOMScrollHandler();
return;
}
displayResultDOM.value += thisElementValue;
displayResultDOMScrollHandler();
}
function displayResultDOMScrollHandler() {
displayResultDOMScrollX = displayResultDOM.scrollWidth - displayResultDOMScrollWidth;
displayResultDOM.scrollLeft = displayResultDOMScrollX;
}
function equalDOMHandler() {
const mathOperation = displayResult.value;
const result = eval(mathOperation);
if(!isFinite(result)){
alert("امکان محاسبه این عملیات ریاضی وجود ندارد !");
return;
}
displayResult.value = result;
}
function clearDOMHandler() {
displayResult.value = "";
}
function backspaceDOMHandler() {
let mathOperation = displayResult.value;
mathOperation = mathOperation.substring(0, (mathOperation.length) - 1);
displayResult.value = mathOperation;
}
// helpers
function loopThrowDOMS(doms, funcHandler) {
const tmpDOMS = Array.from(doms);
tmpDOMS.forEach(funcHandler);
}
function loopThrowObject(obj, funcHandler) {
const tmpObjectKeys = Object.keys(obj);
tmpObjectKeys.forEach(funcHandler);
}
- در بخش DOM از element های مورد نیاز مان دسترسی خواهیم گرفت با استفاده از id و class
- Property ها شامل ScrollX یا همان بخش scroll افقی نمایشگر اطلاعات ریاضی هست
- set handler برای دکمه های ماشین حساب در زمانی که فشرده شدن عملی را انجام دهد ، همچنین برای زمانی که صفحه کلید فشرده شد تابعی را تعریف می کنیم
- قسمت handlers شامل توابعی هست جهت کنترل کلید های صفحه کلید و دکمه های خود ماشین حساب و حالت روشن / تاریک ماشین حساب
- darkModeDOMChangeHandler تابعی برای تغییر از حالت روشن به تاریک یا برعکس
- globalKeyPressedHandler برای انجام عملیات ریاضی از طریق صفحه کلید فیزیکی
- buttonsDOMClick برای کنترل دکمه های ماشین حساب در زمانی که کلیک شود
- displayResultDOMScrollHandler زمانی که مقدار داده های نمایشی زیاد شود نیاز است که برای نمایش آخرین اعداد کاربر scroll شود که با این تابع امکان پذیر است .
- equalDOMHandler زمانی که = زده شود یا دکمه Enter زده شود محاسبه را انجام داده و عدد نهایی را نمایش می دهد
- clearDOMHandler در صورتی که دکمه C زده شود با این تابع تمامی مقادیر را reset یا پاک می کنیم
- backspaceDOMHandler زمانی که میخواهیم یک عمل به قبل برگردیم مثلا 123 را با این تابع به 12 تبدیل و نمایش می دهیم
- helpers : شامل توابع کمکی است که در توسعه راحت تر برنامه ما را یاری می کند
- loopThrowDOMS : جهت چرخش در بین element هایی که دارای یک کلاس می باشند
- loopThrowObject : جهت چرخش در object ها
فایل main.css جهت استایل دادن به برنامه
#calculator{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #fff;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2), 0 6px 20px 0 rgba(0,0,0,0.2);
border-radius: 14px;
padding-bottom: 20px;
width: 320px;
}
#calculator.dark{
background: #6b6969;
}
.display {
width: 100%;
height: 60px;
padding: 40px 0;
background: #FF0509;
border-top-left-radius: 14px;
border-top-right-radius: 14px;
}
.buttons {
padding: 20px 20px 0 20px;
}
.row {
width: 280px;
float: left;
}
.func-btn {
width: 60px;
height: 60px;
float: left;
padding: 0;
margin: 5px;
box-sizing: border-box;
background: #ecedef;
border: none;
font-size: 30px;
line-height: 30px;
border-radius: 50%;
font-weight: 700;
color: #5E5858;
cursor: pointer;
}
.wid-2{
width: 130px;
border-radius: 4px;
}
.func-btn.dark{
background: #424242;
color: #fff;
border: 1px solid #fff;
}
input[type=text] {
width: 270px;
height: 60px;
float: left;
direction: ltr;
text-align: left;
padding: 0;
box-sizing: border-box;
border: none;
background: none;
color: #ffffff;
font-weight: 700;
font-size: 60px;
line-height: 60px;
margin: 0 25px;
outline: none;
}
.red {
background: #FF0509 !important;
color: #ffffff !important;
}
.red.dark{
border:1px solid #FF0509;
}
ارسال نظر