原生JavaScript实现的简易计算器

最近一直没有写博客
因为一直忙着预习考试内容
什么偏微分啊、数值分析啊、计算机图形学啊、信息论…
在未来一个月可能会很忙
整理前端的频率可能就没那么高了


还是说正题
昨天晚上用JavaScript实现了一个简易的计算器
今天分享给大家

这个计算器长成这个样子

原生JavaScript实现的简易计算器_第1张图片

或者可以去我的github查看
没有考虑什么兼容,浏览器环境为chrome

→传送门←

src="https://paysontsung.github.io/web-front-end-study/%E5%8E%9F%E7%94%9Fjs%E7%AE%80%E6%98%93%E8%AE%A1%E7%AE%97%E5%99%A8/calculator.html" width="360" height="480">

HTML/结构


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算器title>
    <link rel="stylesheet" href="styles/calculator.css">
head>
<body>
    <div class="calculator">
        <div class="c_screen">
            <p>p>
        div>
        <div class="c_btn_wrapper">
            <div class="c_row">
                <button class="c_func_btn">(button>
                <button class="c_func_btn">)button>
                <button class="c_func_btn">CEbutton>
                <button class="c_func_btn">ACbutton>
            div>
            <div class="c_row">
                <button>7button>
                <button>8button>
                <button>9button>
                <button class="c_func_btn">/button>
            div>
            <div class="c_row">
                <button>4button>
                <button>5button>
                <button>6button>
                <button class="c_func_btn">xbutton>
            div>
            <div class="c_row">
                <button>1button>
                <button>2button>
                <button>3button>
                <button class="c_func_btn">-button>
            div>
            <div class="c_row">
                <button>0button>
                <button>.button>
                <button class="c_func_btn">=button>
                <button class="c_func_btn">+button>
            div>
        div>
    div>
    <script src="scripts/calculator.js">script>
body>
html>

关于html结构就没必要多说了
div嵌套div,计算器大体就分为显示屏和按钮组两部分
按钮的实现我选择了button标签

CSS/表现

.calculator {
    width: 326px;
    height: 460px;
    margin: 250px auto;
    background-color: #368590;
    border-radius: 5px;
    box-shadow: 0 2px 15px black;
    overflow: hidden;
}
.calculator .c_screen {
    position: relative;
    width: 326px;
    height: 110px;
    background-color: #96a4c2;
    border-radius: 5px;
    box-shadow: inherit;
}
.calculator .c_screen>p {
    position: absolute;
    top: 50%;
    margin-top: -28px;
    width: 236px;
    text-align: center;
    word-break: break-all;
    color: #fff;
    font-size: 20px;
    font-weight: bold;
    padding: 10px 45px;
}
.calculator .c_row {
    margin: 0 23px;
}
button {
    cursor: pointer;
    width: 60px;
    height: 45px;
    margin: 20px 2px 0;
    border: 0px;
    border-radius: 5px;
    color: #fff;
    background-color: #2b2f5b;
    outline: none;
}
button::selection {
    color: #fff;
}
button:active {
    box-shadow: 0 0 5px 5px dodgerblue;
}
.c_func_btn {
    background: linear-gradient(to bottom, rgba(252,156,23,1) 0%, rgba(247,126,27,1) 100%);
}

CSS部份也很简单
有些部分我稍微解释一下


.calculator {
    ...
    overflow: hidden;
}

添加这个属性是防止显示屏的阴影设置和整体计算器的阴影设置叠加


.calculator .c_screen {
    ...
    box-shadow: inherit;
}

这个地方我偷个懒,直接选择继承了父级的盒阴影属性
这个inherit属性值可能很多同学会忽略


.calculator .c_screen>p {
    position: absolute;
    ...
}

这里我为了解决margin塌陷问题
选择使用绝对定位触发bfc


button {
    cursor: pointer;
    ...
    border: 0px;
    ...
    outline: none;
}

对于所有按钮,设置pointer光标很有必要
对于button标签,浏览器有默认的border和outline
我们不需要它们,所以设置0px、none


button::selection {
    color: #fff;
}

这个样式同样是为了消除浏览器默认行为
就是文本选中的颜色和背景色
这里我们手动设置颜色为白色
就不会有选中文本的行为


button:active {
    box-shadow: 0 0 5px 5px dodgerblue;
}

这个样式就是为了让我们点击按钮有高亮的显示


JavaScript/行为

var btn_wrap = document.getElementsByClassName('c_btn_wrapper')[0], // 按钮容器
    content = document.getElementsByTagName('p')[0], // 显示器内容
    count = 0, //记录显示屏上字符及数字个数
    bOneDec = false; //表示显示屏一个数字中是否已经有一个小数点的状态
btn_wrap.onclick = function(e){
    var target = e.target;
    if(target.nodeName.toLowerCase() === 'button'){
        var btnType = target.innerText;
        if(content.innerText == 'Math Error' && btnType != 'AC'){
            return;
        }
        if(btnType == 'AC'){
            bOneDec = false;
            content.innerText = '0';
            count = 1;
        }else if(btnType == 'CE'){
            if(content.innerText != ''){
                if(content.innerText.length === 1){
                    content.innerText = '0';
                }else{
                    content.innerText = content.innerText.slice(0,-1);
                }
                count--;
            }
        }else if(btnType == '='){
            var text = content.innerText;
            if(!text){
                return;
            }else{
                text = text.replace(/x/g,'*');
                var result;
                try{
                    result = eval(text) + '';
                    if(result.search(/\./) > 0){
                        bOneDec = true;
                        if(result.split('.')[1].length > 5){
                            result = (+result).toFixed(5);
                        }
                    }
                    content.innerText = result;
                    count = result.length;
                }catch(e){
                    content.innerText = 'Math Error';
                }
            }
        }else{
            if(isNaN(+btnType) && btnType != '.'){
                bOneDec = false;
            }
            if(btnType == '.'){
                if(bOneDec){
                    return;
                }
                bOneDec = true;
            }
            if(content.innerText == '0' && (!isNaN(+btnType) ||
            btnType == '(' || btnType == ')')){
                content.innerText = '';
            }
            content.innerText += btnType;
            if(count++ >= 44){
                alert('输入的字符过多');
            }
        }   
    }
}

我的js代码就两部分
声明五个变量,绑定一个事件
变量代表的意义已经写在注释里了

btn_wrap.onclick = function(e){
    var target = e.target;
    ...
}

这样的写法一看就知道我使用了事件委托
下面我来具体说说这块代码
首先是大体结构分析

if(target.nodeName.toLowerCase() === 'button'){ 
//↑上面这个判断表示只有当我的节点是button标签才做进一步判断
    var btnType = target.innerText;  //←这个局部变量通过我button标签的内容判断了按钮类型
    if(content.innerText == 'Math Error' && btnType != 'AC'){
        return;
    }   //↑如果我的显示屏显示了“Math Error”并且我点击的按钮不是AC归零键,那么直接返回,不响应
    if(btnType == 'AC'){
        ...
    }else if(btnType == 'CE'){
        ...
    }else if(btnType == '='){
        ...
    }else{
        ...
    }
    //↑然后通过判断我当前点击的按钮类型做进一步判断
}

下面就是通过判断不同的按钮做不同处理
对于AC键比较简单
AC键是重置的按键
这就类似于初始化
所以

bOneDec = false; //←对于小数点的布尔变量赋予假值
content.innerText = '0';  //←设置屏幕内容为0
count = 1;  //←计数器重置为1

CE键是回撤键
回删一个数字或符号

if(content.innerText != ''){
//↑首先最重要的判断是我们的显示器必须有内容
    if(content.innerText.length === 1){
        //↑如果显示器中只有一个数字,那么就直接变成0
        content.innerText = '0';
    }else{
        //↓通过字符串的slice原型方法来回删最后一个数字或符号
        content.innerText = content.innerText.slice(0,-1);
    }
    count--;  //←不要忘了计数器-1
}  

按下了=等号,计算器就要进行计算

var text = content.innerText; // ←先把屏幕内容缓存下来
if(!text){   //←屏幕上什么也没有,那就直接返回吧
    return;
}else{
    text = text.replace(/x/g,'*'); //←如果屏幕中有x那么替换成我们用的*
    var result; //←缓存计算结果
    try{
        result = eval(text) + ''; //←计算结果转换为字符串
        if(result.search(/\./) > 0){ //←判断结果中是否有小数点
            bOneDec = true; //初始化小数点判断布尔变量
            if(result.split('.')[1].length > 5){
                result = (+result).toFixed(5);
            }//↑如果结果中有小数点并且小数点后超过五位那么结果只保留五位小数
        }
        content.innerText = result; //←屏幕上要显示我们结果
        count = result.length; //←修改计数器的值
    }catch(e){
        content.innerText = 'Math Error'; //←如果计算报错了,那么在屏幕上显示错误信息
    }
}

在最后一项判断中就是对数字键以及加减乘除等等的处理了

if(isNaN(+btnType) && btnType != '.'){
    bOneDec = false;
} //↑如果点击的不是数字键也不是小数点,那么小数点判断的锁要打开
if(btnType == '.'){ //←小数点判断
    if(bOneDec){ //←既然当前数字中已经有小数点了,就不能重复添加,计算器不响应
        return;
    }
    bOneDec = true; //←表示当前数字已经有小数点了
}
if(content.innerText == '0' && (!isNaN(+btnType) || 
btnType == '(' || btnType == ')')){
    content.innerText = '';
}//↑如果屏幕上是0,而我们正要按数字键或者是括号,那么先把屏幕上的0去掉
content.innerText += btnType; //←按什么屏幕上就多显示什么
if(count++ >= 44){
    alert('输入的字符过多');
} //↑计数器最后用在了这里,如果字符太多了,弹出警告

以上就是原生JavaScript实现的简易计算器
在整理的过程中
我也发现以前写的代码还有可以优化的地方
修改之后不知道还有没有bug
如果有的话,还请大家指出

==主页传送门==

你可能感兴趣的:(Web前端,JavaScript-ES3)