js之win10计算器

前不久完成了win10计算器的页面布局(HTML+CSS),这时间我学习了js的一些技术,现在我继续完成其js部分。
为了便于功能显示,在页面布局部分的代码在上次部分做了稍微改动。
完整代码如下:




    
    
    
    calculator
    


    
//新增表达式显示屏(初始时无显示)
0
  • MC
  • MR
  • M+
  • M-
  • MS
  • %
  • (
  • )
  • 1/x
  • CE
  • C
  • DEL
  • /
  • 7
  • 8
  • 9
  • *
  • 4
  • 5
  • 6
  • -
  • 1
  • 2
  • 3
  • +
  • +/_
  • 0
  • .
  • =
//引入js文件
* {
    margin: 0;
    padding: 0;
}

.calculator {
    width: 400px;
    height: 100%;
    background-color: rgb(241, 241, 241);
    overflow: hidden;
    margin: 0 auto;
    //为了美观,适当减少弯角曲率
    border-top-left-radius: 10%;
    border-top-right-radius: 10%;
}

.screen1 {//新增的显示屏的样式
    height: 50px;
    line-height: 50px;
    margin-top: 50px;
    font-size: 20px;
    color: yellowgreen;
}
.screen2 {
    height: 100px;
    font-size: 50px;
    line-height: 100px;
    color: #000;
    font-weight: 600;
}
span {
    float: right;
}

.M {
    margin-top: 20px;
    height: 30px;
}

.M li {
    width: 65px;
    line-height: 30px;
    list-style: none;
    float: left;
    text-align: center;
    font-size: 10px;
}

.m {
    color: rgb(192, 192, 192);
}

.m1 {
    font-weight: 600;
}

.c1{
transition: all 0.5s;
}
.c1:hover {
    background-color: rgb(214, 212, 212);
}

.row {
    height: 80px;
}

.row li {
    width: 100px;
    height: 80px;
    line-height: 70px;
    list-style: none;
    float: left;
    text-align: center;
    border: 2px solid rgb(241, 241, 241);
    box-sizing: border-box;
}

.u1 {
    font-size: 20px;
    background-color: rgb(245, 245, 245);
}

.u2 {
    font-size: 25px;
    font-weight: 700;
    background-color: rgb(255, 255, 255);
}

(页面布局部分的具体详情可以点击以下链接win10计算器页面布局)
在开始编写js代码前,首先得明确此功能实现中最重要的两个问题:

  1. 如何找到鼠标点击了哪个li
  2. 如何把结果传给显示屏

对于问题1的处理方法:通过e.target.innerText得到点击事件的li里面的文本内容,然后通过比较来确定执行相应的功能逻辑。
对于问题2的处理方法:document.getElementsByClassName(className)[0].getElementsByTagName(“span”)[0].innerText,它就可以设置显示屏应要显示的内容。
处理掉这两个问题后,实现功能就易如反掌了。

function my$(className) {
    return document.getElementsByClassName(className);
}
var strs = my$("c1");
var flag = false;
for (var i = 0; i < strs.length; i++) {
    strs[i].onclick = function (e) {
        var str = e.target.innerText;
        var tmp = my$("screen1")[0].getElementsByTagName("span")[0].innerText;
        if (str === "=") {
            var a = calculate(tmp);
            //小数显示不下
            my$("screen2")[0].getElementsByTagName("span")[0].innerText = a;
            flag = true;
        } else if (str === "DEL") {
            if (flag) {
                my$("screen1")[0].getElementsByTagName("span")[0].innerText = "";
                flag = false;
            } else {
                tmp = tmp.substring(0, tmp.length - 1);
                my$("screen1")[0].getElementsByTagName("span")[0].innerText = tmp;
            }
        } else if (str === "C" || str === "CE") {
            if (str === "C" || flag) {
                my$("screen1")[0].getElementsByTagName("span")[0].innerText = "";
                my$("screen2")[0].getElementsByTagName("span")[0].innerText = 0;
                flag = false;
            } else {
                my$("screen2")[0].getElementsByTagName("span")[0].innerText = 0;
            }
        } else {
            if (flag) {
                tmp = my$("screen2")[0].getElementsByTagName("span")[0].innerText;
                flag = false;
            }
            if (tmp === "") {
                my$("screen1")[0].getElementsByTagName("span")[0].innerText = str;
            } else {
                my$("screen1")[0].getElementsByTagName("span")[0].innerText = tmp + str;
            }
        }
    }
}

//算数算法
var calculate = function (s) {
    var stack = new Array();
    for (var i = 0; i < s.length; i++) {
        var tmp = s[i];
        if (tmp >= '0' && tmp <= '9') {
            var r = getNum(s, i);
            dealNum(s, stack, r.num);
            i = r.index;
        } else if (tmp === '+' || tmp === '-' || tmp === '*' || tmp === '/' || tmp === '(') {
            stack.push(tmp);
        } else if (tmp === ')') {
            dealRight(s, stack);
        }
    }
    return getFinalResult(stack);
};

var getNum = function (s, i) {
    var start = i;
    while (i < s.length && ((s[i] >= '0' && s[i] <= '9') || s[i] === '.')) {
        i++;
    }
    return {
        num: Number(s.substring(start, i)),
        index: i - 1
    };
};

var dealNum = function (s, stack, num) {
    if (stack.length !== 0 && (stack[stack.length - 1] === '*' || stack[stack.length - 1] === '/')) {
        var sign1 = stack.pop();
        var pre1 = stack.pop();
        var res = sign1 === '*' ? pre1 * num : pre1 / num;
        stack.push(res);
    } else {
        stack.push(num);
    }
}

var dealRight = function (s, stack) {
    var result = 0;
    //括号里面只有+/-运算
    while (stack[stack.length - 1] !== '(') {
        var next1 = stack.pop();
        if (stack.length === 0 || stack[stack.length - 1] === '(') {
            result += next1;
            break;
        }
        var sign2 = stack.pop();
        result = sign2 === '+' ? result + next1 : result - next1;
    }
    stack.pop();
    var res2 = 0;
    //使得stack里面只有+/-运算符,保证算法优先级(原因:完成括号运算后的结果必然是一个数字)
    while (stack.length !== 0 && (stack[stack.length - 1] === '*' || stack[stack.length - 1] === '/')) {
        var sign3 = stack.pop();
        var pre2 = stack.pop();
        res2 = sign3 === '*' ? pre2 * result : pre2 / result;
        result = res2;
    }
    stack.push(result);
}

var getFinalResult = function (stack) {
    var result = 0;
    while (stack.length > 0) {
        var next = stack.pop();
        if (stack.length === 0) {
            return result + next;
        }
        var sign = stack.pop();
        result = sign === '+' ? result + next : result - next;
    }
    return result;
};

解释几个地方:

  1. 由于显示屏的大小以及字体的大小设置不合理而产生如下情况的bug(interesting)js之win10计算器_第1张图片
  2. 这里面还有部分功能未实现(包括部分点击事件,算数算法没有支持正负数以及异常输入和异常结果的处理)
  3. 算法部分我采用的是自己编写的算数算法,如果有不懂可以看leetcode772题–基本计算器 III(这题是困难难度,其实就是1,2的综合版),此算法的思路来源 算法思路。

你可能感兴趣的:(前端)