计算器的主要作用是进行数字运算,开发一个计算器功能的web实例,有助于更好的掌握js基础的数字运算能力。
本实例详细分析一个js计算器的开发步骤,学习本教程时最好先具备一些基础的js知识。
计算器包括显示数字区域和按键区域两大部分,先把计算器的这两个区域的html元素编写出来,如下所示:
<div class="calculator_wrap" id="calculator"><!--计算器外包元素--> <div class="show_num"><!--显示数字区域--> <div class="num_save" id="numSave"></div><!--计算公式--> <div class="num_cur" id="numCur">0</div><!--计算结果--> <div class="show_m" id="showM">M</div><!--记忆存储标志--> </div> <div class="btn_wrap" id="btnWrap"><!--按钮区域--> <div class="btn" data-key="MC">MC</div><!--记忆清零--> <div class="btn" data-key="MR">MR</div><!--记忆读取--> <div class="btn" data-key="MS">MS</div><!--存储记忆--> <div class="btn" data-key="MA">M+</div><!--记忆加--> <div class="btn" data-key="ML">M-</div><!--记忆减--> <div class="btn" data-key="BACK">←</div><!--退格--> <div class="btn" data-key="CE">CE</div><!--清除当前--> <div class="btn" data-key="Clear">C</div><!--清除--> <div class="btn" data-key="Negate">±</div><!--正负转换--> <div class="btn" data-key="Square">√ ̄</div><!--平方根--> <div class="btn" data-key="Num" data-value="7">7</div><!--7--> <div class="btn" data-key="Num" data-value="8">8</div><!--8--> <div class="btn" data-key="Num" data-value="9">9</div><!--9--> <div class="btn" data-key="Base" data-value="/">/</div><!--除--> <div class="btn" data-key="Percentage">%</div><!--百分号--> <div class="btn" data-key="Num" data-value="4">4</div><!--4--> <div class="btn" data-key="Num" data-value="5">5</div><!--5--> <div class="btn" data-key="Num" data-value="6">6</div><!--6--> <div class="btn" data-key="Base" data-value="*">*</div><!--乘--> <div class="btn" data-key="Reciprocal">1/x</div> <!--倒数--> <div class="btn" data-key="Num" data-value="1">1</div><!--1--> <div class="btn" data-key="Num" data-value="2">2</div><!--2--> <div class="btn" data-key="Num" data-value="3">3</div><!--3--> <div class="btn" data-key="Base" data-value="-">-</div><!--减--> <div class="btn equal" data-key="Equal">=</div><!--等于--> <div class="btn zero" data-key="Num" data-value="0">0</div><!--0--> <div class="btn" data-key="Point">.</div><!--小数点--> <div class="btn" data-key="Base" data-value="+">+</div><!--加--> </div> </div>
读者可以自己编写一些样式,设计一个自己喜欢的计算器效果。本实例的计算器效果如下图所示:
样式代码:
.calculator_wrap{width:240px;height:360px;padding:10px;margin:30px auto;border:1px solid #8acceb;background:#d1f1ff;} .calculator_wrap .show_num{position:relative;padding:0 8px;height:60px;background:#fff;text-align:right;} .calculator_wrap .show_m{position: absolute;left:10px;bottom:3px;display:none;} .calculator_wrap .num_save{height:26px;line-height:26px;font-size:12px;white-space:nowrap;} .calculator_wrap .num_cur{font-size:28px;height:34px;line-height:34px;} .calculator_wrap .btn_wrap{font-size:0px;} .calculator_wrap .btn{display:inline-block;width:38px;height:38px;line-height:38px;text-align:center;border:1px solid #ccc;background:#666;color:#fff;font-size:14px;margin:10px 10px 0 0;cursor:pointer;} .calculator_wrap .btn:hover{background:#333;} .calculator_wrap .btn:nth-child(5n){margin-right:0px;} .calculator_wrap .equal{position:absolute;height:90px;line-height:90px;} .calculator_wrap .zero{width:90px;}
对于新手来说,计算器功能看起来好像很复杂,那么多按钮、多种计算方式,不知如何开始。其实任何一个功能,只需要理清楚思路,一步一步编写代码,会发现实现起来都不难。
1 获取各个html元素
web前端不论要在页面上做什么,都要先获取页面上的各个DOM元素。看起来整个计算器的按钮较多,实际开发中可以使用事件代理来操作按钮,所以只获取所有按钮的容器元素即可。代码如下:
//获取外包元素 var eCalculator = document.getElementById('calculator'); //保存运算数据(公式)容器 var eNumSave = document.getElementById('numSave'); //当前数字容器 var eNumCur = document.getElementById('numCur'); //按钮外部容器,用于事件代理 var eBtnWrap = document.getElementById('btnWrap'); //记忆存储标志元素 var eShowM = document.getElementById('showM');
2 声明相关变量
在运算过程中,需要一些变量来进行辅助计算、存储结果和判断等,如下所示:
//运算公式 var sStep = ''; //当前数字 var sCurValue = '0'; //运算结果 var nResult = null; //运算符 var sMark = ''; //MR记忆存储数据 var nMvalue = 0; //输入状态。false:输入数字替换原数字;true:输入数字加到原数字后面; var bLogStatus = false;
3 按键上添加点击事件
因为整个计算器按键较多,每一个按钮都单独绑定一个事件会显得太多,很繁琐,还会影响性能,且容易出错。所以刚才只获取了按键的外部容器 eCalculator。
再使用事件代理,就只需要在容器上添加点击事件,判断当前点击的按键是哪一个,再执行对应的计算即可。用鼠标点击按键的时候,可能会因为点得太快而选择了按键上的文字,因此还需要在外包容器上添加一个阻止默认行为的操作,代码如下所示:
//外包容器添加鼠标按下事件,用于防止选中文字 eCalculator.addEventListener('mousedown',function(event){ //阻止鼠标按下时的默认行为,防止点击按钮过快时选中文字 event.preventDefault(); }); //按键容器添加点击事件,用于代理所有按键的操作 eBtnWrap.addEventListener('click',function(event){ });
3.1 获取点击的按键和值
通过事件函数传入的event参数,可以获取到鼠标点击的元素。再通过元素上的data-key和data-value属性判断鼠标点击的是哪一个按键以及它的值,如下所示:
eBtnWrap.addEventListener('click',function(event){ //获取点击的元素 var eTarget = event.target; //判断按下的键 var key = eTarget.dataset.key; //获取按下的值 var value = eTarget.dataset.value; });
3.2 判断按键及值,数字键和小数点执行输入操作
如果按键属性data-key是'Num'表示按下的是数字,'Point'表示小数点。
这些按键都是执行输入,因为数字有多个,所以把数字输入封装到fnInputNum函数中。再封装fnShowResult函数把数据显示到显示数字区域。如下所示:
eBtnWrap.addEventListener('click',function(event){ /* … */ //判断点击的是否是按键 if(key){ //用switch语句判断不同的按键执行对应的操作 switch(key){ //数字键执行操作 case 'Num': fnInputNum(value); break; //小数点操作 case 'Point': //判断是否有已小数点,用于限制只能输入一个小数点 if(sCurValue.indexOf('.')==-1){ sCurValue = sCurValue + '.'; bLogStatus = true; } break; } //显示数据到显示数字区域 fnShowResult(); } }); //输入数字 function fnInputNum(num){ //根据输入状态判断是替换当前数字还是添加到当前数字后面 if(bLogStatus){ sCurValue = sCurValue + num; }else{ //限制第一个数字不能是0 if(num!=0){ bLogStatus = true; } sCurValue = num; } } //显示计算结果 function fnShowResult(){ //显示计算公式 eNumSave.innerHTML = sStep; //限制数字总长度 if(sCurValue.length>14){ sCurValue = sCurValue.slice(0,14); } //显示当前数字 eNumCur.innerHTML = sCurValue; }
这时候已经可以点击数字和小数点,输入到计算器显示屏上,如图所示:
3.3 加减乘除运算
计算器最基本的就是加减乘除运算。为了实现对数字进行加减乘除并计算结果功能,封装fnCountResult、fnBaseCount和fnEqual三个函数。
fnCountResult用于根据运算符计算结果;
fnBaseCount修改计算公式或计算结果;
fnEqual用于按下=号时计算结果,并重置数据。如下所示:
eBtnWrap.addEventListener('click',function(event){ /* … */ //判断点击的是否是按键 if(key){ //用switch语句判断不同的按键执行对应的操作 switch(key){ /* … */ //加减乘除基本运算 case 'Base': fnBaseCount(value); break; //等于 case 'Equal': fnEqual(); break; } //显示数据到显示数字区域 fnShowResult(); } }); //计算结果 function fnCountResult(){ //判断当前运算符并执行运算 switch(sMark){ case '+': nResult = nResult===null"text-align: center">3.4 再给其他按键添加操作,代码如下所示:
eBtnWrap.addEventListener('click',function(event){ /* … */ //判断点击的是否是按键 if(key){ //用switch语句判断不同的按键执行对应的操作 switch(key){ /* … */ //清除 case 'Clear': fnClear() break; //退格 case 'BACK': fnBack(); break; //CE case 'CE': //清空当前显示数值 sCurValue = '0'; bLogStatus = false; break; //取反 case 'Negate': //当前数值取反 sCurValue = ''+(-sCurValue); break; //取平方根 case 'Square': //当前数值取平方根 nResult = Math.sqrt(+sCurValue); //其他数据初始化 sCurValue = ''+nResult; sStep = ''; sMark = ''; bLogStatus = false; break; //倒数 case 'Reciprocal': //当前数值取倒数 //其他数据初始化 nResult = 1/sCurValue; sCurValue = ''+nResult; sStep = ''; sMark = ''; bLogStatus = false; break; //M系列 case 'MC': //记忆数值清零 nMvalue = 0; fnShowM() break; case 'MR': //显示记忆数值 sCurValue = '' + nMvalue; fnShowM() break; case 'MS': //记忆数值改为当前数值 nMvalue = +sCurValue; fnShowM() break; case 'MA': //当前数值加到记忆数值中 nMvalue += +sCurValue; fnShowM() break; case 'ML': //从记忆数值中减去当前数值 nMvalue -= +sCurValue; fnShowM() break; } //显示数据到显示数字区域 fnShowResult(); } }); //清除 function fnClear(){ //初始化所有数据 sStep = ''; sCurValue = '0'; nResult = null; sMark = ''; bLogStatus = false; } //退格 function fnBack(){ //必须是输入状态才可以退格 if(bLogStatus){ //减去数值最后一位数 sCurValue = sCurValue.slice(0,sCurValue.length-1); //如果最后数值为空或负号(-),改为0,重置输入状态为false,不可再退格 if(sCurValue==''||sCurValue=='-'){ sCurValue = '0'; bLogStatus = false; } } } //判断是否有M记忆存储 function fnShowM(){ bLogStatus = false; //判断是否显示记忆存储标志 eShowM.style.display = nMvalue==0"htmlcode">//键盘事件 document.addEventListener('keyup',function(event){ //获取当前键盘按键 var key = event.key; //获取按键code var code = event.keyCode; //限制正确的按键才修改显示的数据 var comply = false; //输入数字 if((code>=48&&code<=57)||(code>=96&&code<=105)){ fnInputNum(key); comply = true; } //加减乘除 if( key=='*'||key=='+'||key=='/'||key=='-'){ fnBaseCount(key); comply = true; } //esc键 if(code==27){ fnClear(); comply = true; } //回车键 if(code==13){ fnEqual(); comply = true; } //退格键 if(code==8){ fnBack(); comply = true; } if(comply){ //显示数据到计算器屏幕 fnShowResult(); } });一个简单的计算器就完成了,如果以学习为目的话,建议不要直接复制代码,最好直接手动输入代码及注释,加深印象和提高学习效果。
总结
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】