Implementing native web calculators with 84.7% native js: Harness the power of JS in the browser

Implementing native web calculators with 84.7% native js: Harness the power of JS in the browser

javascript

Description

This document focuses on how to implement a web calculator in browser view using native js to minimize the use of HTML tags.

After reading this document, you will learn:

✔️Learn how to use the basic browser api to get DOM objects

✔️Use js built-in functions to achieve the basic operations of the calculator

✔️Use css for simple, personalized, adaptive layouts.

Personal information and something to write ahead

NOTICE:This document is based on my own experience and does not refer to other technical documents.

Before I start this documentation tutorial, I need to insert some basic information about the individual here, because this is a course assignment.

The Link Your Classhttp://t.csdnimg.cn/xdDRg
The Link of Requirement of This Assignmenthttp://t.csdnimg.cn/mt5IU
The Aim of This AssignmentPLEASE READ THE TITLE
MU STU ID and FZU STU ID<21126135_832102117>

The following is my github homepage and the respository address of this course:

And I would like to apologize to the TA who graded this assignment: I submitted this assignment late due to my participation in the software development Design competition (responsible for the front-end part), but fortunately I did it before the deadline. If there are any mistakes in this document, please feel free to point them out.

Catalogue

  1. Results display (to be improved)
  2. PSP Form
  3. Solution Idea
  4. Design and Implementation&Code Description
  5. Summary

Results display (to be improved)

img

It’s pretty rudimentary, but there’s really no time, qwq.

PSP Form

Personal Software Process StagesEstimated Time(minutes)Actual Time(minutes)
Planning154
• Estimate154
Development240290
• Analysis105
• Design Spec105
• Design Review105
• Coding Standard55
• Design55
• Coding160200
• Code Review1010
• Test3055
Reporting5051
• Test Repor1013
• Size Measurement1525
• Postmortem & Process Improvement Plan2513
Sum305349

Solution Idea

In front-end development, you may be interested in the rendering process of browser DOM elements, but sometimes you don’t understand how it actually works.

HTML tags are very useful. It simplifies the actual amount of code and lets developers present what they want in the browser.

However, as a programmer, we need to have a deep understanding of how browsers work.

Remember javascript? It controls the basic logic of the browser. The core of the browser also includes a javascript parser, which allows users to write code to display the contents of the calculator.

As a novice who has learned front-end development for more than a year, I have not written native browser js code for a long time, even if Node.js has been writing, but it will inevitably be rusty.

So, when I saw this assignment, I immediately planned the following plan:

  1. Use native js code and try to avoid html tags
  2. Design a css calculator style, and design a manuscript, including the screen display effect of each webpage (mobile phone, computer), and consider using media query to achieve self-adaptation;
  3. The core calculation logic of the calculator and the interaction design of the button can use the weak type of js to design multiple related functions and return the calculation results of the form

So the difficulty is still in the logic of the calculator, I think briefly, clear the basic implementation process of the calculator:

  1. First, the operand or compute must be separated from the operator

  2. Must be in accordance with the existing calculation order, multiply and divide first, then add and subtract

  3. Operands with special symbols are processed and computed preferentially

  4. Once the user enters an incorrect calculation number, the calculation must be terminated and an error must be returned

    img

Design and Implementation&Code Description

HTML

Since I want to reduce the amount of html code, I will not write too many html tags, and simply divide the two areas: the button area and the display area.

Both css and js were introduced with external links.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>My Calculator</title>
        <link href="./Style.css" rel="stylesheet" type="text/css" />
    </head>

    <body>
        <div class="outer">
            <div class="base">
                <div class="display-zone"><input type="text" id="input"
                        onfocus="this.blur()"
                        value></div>
                <div class="operation-zone"></div>
            </div>
        </div>
    </body>
    <script src="./Operation.js"></script>
</html>
CSS Design

Because it is a small task, so I did not think too much about the style of css, or I used my favorite yellow as the main color.

The most important thing to consider is the adaptation of the screen, and it is best to use relative units (such as rem, em) to avoid the use of absolute units such as px.

* {
    margin: 0;
    padding: 0;
}

body {
    display: flex;
    justify-content: center;
    background-color: lightyellow;
}

.outer {
    margin-top: 5vh;
    height: 80vh;
    width: 45vw;
    background-image: url(./assets/img/pikachu.jpeg);
    background-repeat: no-repeat;
    background-size: cover;
    border: 6px solid yellow;
    border-radius: 20px;
    padding: 1.2rem;
    display: flex;
    justify-content: center;
    opacity: 60%;
}

.base {
    height: 100%;
    width: 75%;
}

.display-zone {
    height: 25%;
    display: flex;
    align-items: center;
    justify-content: center;
}

#input {
    height: 26%;
    width: 100%;
    font-size: 1.5rem;
    background-color: bisque;
    color: orange;
    font-weight: bolder;
    padding: 0% 1%
}

.operation-zone {
    height: 70%;
}

.btn {
    width: 13%;
    margin: 2% 6%;
    font-size: 1.2rem;
    background-color: bisque;
    border-radius: 1.2rem;
}

.btn:hover {
    background-color: chocolate;
}
Javascript

This part is the focus of the calculator implementation!

First of all, since the entire calculator is to be completed by js, you must consider the following points:

  1. The rendering code associated with DOM elements (buttons) must be written separately from the operation logic, in two different functions
  2. Simplify the main thread and basically execute related functions
  3. Think about what the role of each button is, in addition to a few basic input buttons, as well as clear, back and so on

Once this is done, we can start writing code. Note: Write the function first!

//1.cal()函数负责对输入内容进行基本计算,包括计算顺序、取值,涵盖加减乘除和幂运算等
function calc(value) {
    //定义运算符数组
    let operators = [];
    //使用正则表达式匹配基本运算符号,即加减乘除幂,并将计算数存入数组
    let nums = value.split(/[\+\-\*\/\^]/);
    for (let i = 0; i < value.length; i++) {
        if ((value[i] == '+' || value[i] == '-' || value[i] == '*' || value[i] == '/' || value[i] == '^')) {
            if ((i != 0 && i != value.length - 1) && (value[i + 1] != '+' && value[i + 1] != '-' && value[i + 1] != '*' && value[i + 1] != '/') && value[i + 1] != '^') {
                operators.push(value[i]);
            }
            else if (i == 0 && (value[i] == '+' || value[i] == '-')) {
                nums[0] = '0';
                //对出现在第一位的运算符号判断合理性
                operators.push(value[i]);
            }
            //若不满足匹配条件,则返回error
            else {
                return "error";
            }
        }
    }
    //根据数组和运算符号进行运算,先乘除幂,后加减
    for (let i = 0; i < operators.length; i++) {
        if (numSwitch(nums[i]) != "error" && numSwitch(nums[i + 1]) != "error") {
            if (operators[i] == '*') {
                let product = numSwitch(nums[i]) * (numSwitch(nums[i + 1]))
                nums[i] = "" + product;
                nums.splice(i + 1, 1);
                operators.splice(i, 1);
                i = -1;
            }
            else if (operators[i] == '/') {
                if (numSwitch(nums[i + 1]) != 0) {
                    let division = numSwitch(nums[i]) / (numSwitch(nums[i + 1]))
                    nums[i] = "" + division;
                    nums.splice(i + 1, 1);
                    operators.splice(i, 1);
                    i = -1;
                }
                else { return "error" }
            }
            else if (operators[i] == '^') {
                let power = Math.pow(numSwitch(nums[i]), numSwitch(nums[i + 1]));
                nums[i] = "" + power;
                nums.splice(i + 1, 1);
                operators.splice(i, 1);
                i = -1;
            }
        }
        else { return "error" }
    }

    for (let i = 0; i < operators.length; i++) {
        if (operators[i] == '+') {
            let addition = numSwitch(nums[i]) + (numSwitch(nums[i + 1]))
            nums[i] = "" + addition;
            nums.splice(i + 1, 1);
            operators.splice(i, 1);
            i = -1;

        }
        else if (operators[i] == '-') {
            let substraction = numSwitch(nums[i]) - (numSwitch(nums[i + 1]))
            nums[i] = "" + substraction;
            nums.splice(i + 1, 1);
            operators.splice(i, 1);
            i = -1;
        }
    }
    if (operators[0] == null) {
        return numSwitch(nums[0]);
    }
    else return "error";
}
/*
let newVal = "";
for (let i = 0; i < value.length; i++) {
    let newStr = "";
    if (value[i] == '*' || '/') {
        let leftNum, rightNum, leftIndex = 0;
        let rightIndex = value.length - 1;
        for (let former = i; former >= 0; former--) {
            if (value[i] == '+' || '-') {
                leftIndex = former + 1;
                leftNum = parseInt(value.substring(leftIndex, i));
                break;
            }
        }

        for (let later = i; later < value.length; later++) {
            if (value[i] == '+' || '-' || '*' || '/') {
                rightIndex = later;
                rightNum = parseInt(value.substring(i + 1, rightIndex));
                break;
            }
        }

        if (value[i] == '*') {
            newStr = "" + (leftNum * rightNum);
        }

        else { newStr = "" + (leftNum / rightNum); }
        newVal = value.replace(value.substring(leftIndex, rightIndex), newStr);
        break;
    }
    if (i == value.length - 1) {
        for (let k = 0; k < value.length; k++) {
            let flag = value.length - 1;
            if (value[k] == '+' || '-') {
                for (let h = k; h < value.length; h++) {
                    if (value[h] == '+' || '-') {
                        flag = h;
                        break;
                    }

                }
                if (value[k] == '+') { newStr = "" + parseInt(value.substring(0, k)) + parseInt(value.substring(k + 1, flag)) }
                else { newStr = "" + parseInt(value.substring(0, k)) - parseInt(value.substring(k + 1, flag)) }
                newVal = value.replace(value.substring(0, flag), newStr);
                break;
            }
            if (k == value.length - 1) {
                return value;
            }
        }
    }
}
return calc(newVal);

for (let i = 0; i < 20; i++) {
    let btn = document.createElement("button");
    panel.appendChild(btn);
    btn.setAttribute("class", "btn");
    btn.setAttribute("id", btnNameList[i]);
    let id = btn.getAttribute("id");
    btn.setAttribute("value", id);
    btn.innerHTML = id;
    let addFun = "oper('" + id + "')";
    btn.setAttribute("onclick", addFun);
    adjustBtn(btn);
}
*/

//3.adjustBtn() 调整按钮的数量布局和大小
function adjustBtn(btn) {
    btn.style.height = btn.offsetWidth + "px";
}

//4.initButton() 初始化按钮
function initButton(btnNum) {
    for (let i = 0; i < btnNum; i++) {
        let btn = document.createElement("button");
        panel.appendChild(btn);
        btn.setAttribute("class", "btn");
        //设置DOM元素属性并转化为实际html元素渲染
        btn.setAttribute("id", btnNameList[i]);
        let id = btn.getAttribute("id");
        btn.setAttribute("value", id);
        btn.innerHTML = id;
        let addFun = "oper('" + id + "')";
        btn.setAttribute("onclick", addFun);
        adjustBtn(btn);
    }
}

//5.oper() 按钮绑定事件
function oper(value) {
    let inputZone = document.getElementById("input");
    let input = inputZone.value;

    if (value == '=') {
        inputZone.value = calc(input);
    }
    else if (value == 'B') {
        let newVal = input.substring(0, input.length - 1);
        // document.getElementById("input").setAttribute("value", newVal);
        inputZone.value = newVal;
    }
    else if (value == 'C') {
        // document.getElementById("input").setAttribute("value", "");
        inputZone.value = "";
    }
    else {
        let newVal = input + value;
        inputZone.value = newVal;
    }
}

//6.numSwitch() 对分离的操作数内部进行特殊计算,目前只有sin和cos三角运算,之后补充
function numSwitch(num) {
    let result = 1;
    let regMatchSpecial = /sin|cos/;
    let nums = num.split(regMatchSpecial);
    let operators = num.match(regMatchSpecial);
    if (nums[0] != '') { result *= parseFloat(nums[0]) }
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] == '' || nums[i].split('.').length == 3 || nums[i].split(".")[0] == '') { return "error" }
        switch (operators[i - 1]) {
            case "sin":
                result *= Math.sin(parseFloat(nums[i]) * Math.PI / 180)
                break;
            case "cos":
                result *= Math.cos(parseFloat(nums[i]) * Math.PI / 180)
                break;
            default:
                return "error"
        }
    }
    return result;
}

calc() and switchNum() are the two core functions, swichNum() is responsible for converting the number in character form to the relevant data type, and calc() is responsible for the final calculation.

Once there is a problem with the input, the calculator checks it and returns error directly.


After the function is defined, it is executed directly on the main thread, use initButton(numOfButtons).

//js主线程
var panel = document.getElementsByClassName("operation-zone")[0];
var btnNameList = ["C", "B", "/", "*", "7", "8", "9", "-", "4", "5", "6", "+", "1", "2", "3", "=", ".", "0", "^", "sin", "cos"];
initButton(20);

Perfect! It’s that simple!

img

display

Summary

img

To show the results, JS accounts for 84.7%

The amount of code is not much, but it has basically restored the content of a calculator.

Through the above learning, we make a simple summary:

  • js is superior to other programming languages in terms of flexibility, which is why browsers can parse js
  • When restoring the calculator with pure native code, be careful to separate the code that controls rendering and logic to help us distinguish
  • The calculation logic must be calculated according to the order, using the powerful function or regular expression of js
  • Mastering js is an important threshold for front-end development

let me make a simple summary:

  • js is superior to other programming languages in terms of flexibility, which is why browsers can parse js
  • When restoring the calculator with pure native code, be careful to separate the code that controls rendering and logic to help us distinguish
  • The calculation logic must be calculated according to the order, using the powerful function or regular expression of js
  • Mastering js is an important threshold for front-end development

😁Thanks for reading this document, and I hope you find it helpful!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值