2018-10-9-2018-10-11
这几天用原生JS学习写计算器的过程中,遇到了如下几个问题(按遇到的顺序阐述):
1.静态布局问题
关于这点,如果以后还有布局问题,首先应该考虑到div的排布堆叠问题,计算好每个div的各类参数。关于美感问题,不作考虑,现阶段只关注功能实现问题。
2 JS设计
2.1 在计算器显示屏的显示环节中,缺乏了对JS语言类型的认识,未理解弱语言类型的意思,JS会将同类型的变量相加减 (拼接)。
后面考虑到这点,优化了代码。方法传的是value属性,在按的时候计算符号也可以同步渲染到显示屏中,提高了用户交互性。
2.2
涉及四则运算时,不知道如何将其通过一个“=”按键的点击事件得出一个新的num.value回传,如下图,瞎搞了几天只能得到NaN。
10-11中午看其他人写的代码后,接触到了JS自带的eval()函数
eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
1.该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,那么该方法将不作任何改变地返回。因此不能为 eval() 函数传递 String 对象来作为参数。
2.如果试图覆盖 eval 属性或把 eval() 方法赋予另一个属性,并通过该属性调用它,
则 ECMAScript 实现允许抛出一个 EvalError 异常。
2.3 解决好显示问题之后,比较轻松的解决了清零键问题。
2.4 测试时有时候会按错数字,导致要全盘重输,增加了一个回退键功能。
编写JS方法的过程中,未能很好的把显示屏数值理解通透(实际上就是一个字符串,之前写的那些代码也不算彻底分析清楚如何运作的)。波折之后代码如下:
substring(start,stop) 方法:
返回的子串包括 start 处的字符,但不包括 stop 处的字符。
提取字符串中介于两个指定下标之间的字符。
计划考虑:
一、 增加一个键盘同步输入计算的功能。 (10-13 21:12解决一部分)
1.1 通过事件中的键盘监听 封装了方法,成功实现了数字键输入。
此时遇到了一个问题,当我以如下图单独设置了各个功能键的操作, 是由shift+8构成,键盘输入时不能同时监听到前后两个按键,导致键入后显示为8。
1.2优化了代码,采用switch()语句,提高了阅读性。
1.2 组合键事件(10-14-9:30)
组合按键一般分以下两种:
两位组合建,如:ctrl(cmd)+ 其他按键,alt+其他按键,shift+其他按键
三位组合键,如:ctrl(cmd)+ shift + 其他按键,Ctrl(cmd)+ alt + 其他按键
在组合键中,js的event中有以下几种属性:ctrlKey(metaKey)、altKey、shiftKey
通过组合键事件。
实现了的监听,但显示屏同时输入了8。
(9:33)经过验证,组合事件返回值为布尔值。故将上图函数植入数值8的监听中,处理后可以单独监听8和*的使用。
(9:50)完成了所有非数字键的设定。
1.3 优化了键盘输入模式下的计算优先级,()。
结果为8
结果为5
二、 增加移动端的显示样式(10-13解决)
三、 浮点运算丢失精度(小数),需提升精度。
四、 未考虑低版本IE及其他浏览器的兼容效果。
五、 添加开方、幂次运算、增加计算历史回调功能(即还原当初得结果前的那一步)
5.1 控制台获得历史计算串(利用数组push方法)
5.2 新建个方法,将其投射到新建的ul中
5.2.1动态创建li来一一存放历史计算穿
初步封装一个函数,使得在耗费系统性能的情况下,实现了动态显示的效果,如下图所示。
由控制台输出和函数的设定,每次执行后都会多创造很多的Li。(17:02)
5.2.2 成功实现了精准的历史回显功能,不会造成性能的浪费。
定义了一个全局变量,来控制Li的创建。(21:10)
全局变量破坏了函数的封装性能。函数中如果使用了全局变量,那函数体内的语句就可以绕过函数参数和返回值进行存取,这破坏了函数的独立性,使函数对全局变量产生依赖,也降低了该函数的可移植性。
5.3 设计通过(回显框)点击事件,使得可以之前的某步操作。(10/14 21:51)
通过jQuery的事件代理成功实现。
5.4 多次计算后,会产生过多的高度,需要完善回显框的样子。(10/15 9:00)
在这过程中,发现一个问题。如果不想要那条记录,只能点击回显,而不能删除,影响了用户体验。
5.5 (10:00卒)回显的值是字符串类型(=功能报错),想通过点击一个非字符串标签的想法失败。
以下为源码分享:
<!DOCTYPE html><html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1" >
<title>计算器的实现</title>
</head>
<script src="lib/jquery/jquery.min.js"></script>
<script type="text/javascript">
//定义一个数组来存储历史字符串
var lastNums = [];
//计算器按键封装
function calCulate(val){
var num = document.getElementById("screen");
switch(val){
case "=":
/*
eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
1. 该方法只接受原始字符串作为参数,如果 string 参数不是原始字符串,
那么该方法将不作任何改变地返回。因此请不要为 eval() 函数传递 String 对象来作为参数。
2. 如果试图覆盖 eval 属性或把 eval() 方法赋予另一个属性,并通过该属性调用它,
则 ECMAScript 实现允许抛出一个 EvalError 异常。
*/
lastNums.push(num.value);
showHistroyNum();
num.value = eval(num.value);
break;
case "C":
num.value = "";
break;
default:
num.value = num.value + val;
break;
}
}
//substring(start,stop) 方法返回的子串包括 start 处的字符,但不包括 stop 处的字符。
//提取字符串中介于两个指定下标之间的字符。
delNum = function () {
//获取ID
var screen = document.getElementById("screen");
var str = screen.value;
//截取字符串 (0至倒数第二位)并返回
str = str.substring(0, str.length - 1);
str = (str == "" ? "" : str);
screen.value = str;
};
//定义一个键盘监听按钮
$(document).keydown(function (event) {
var num = document.getElementById("screen");
var e = event || window.event;
var Key = event.keyCode;
switch (Key){
case 48 :
if(e.shiftKey){
val = ")" ;
calCulate(val);
break;
}
getVal(Key);
break;
case 49 :
getVal(Key);
break;
case 50 :
getVal(Key);
break;
case 51 :
getVal(Key);
break;
case 52 :
getVal(Key);
break;
case 53 :
getVal(Key);
break;
case 54 :
getVal(Key);
break;
case 55 :
getVal(Key);
break;
case 56 :
if(e.shiftKey){
val = "*" ;
calCulate(val);
break;
}
getVal(Key);
break;
case 57 :
if(e.shiftKe0y){
val = "(" ;
calCulate(val);
break;
}
getVal(Key);
break;
//功能键区
case 8 :
delNum();
break;
case 187 :
val = "+" ;
calCulate(val);
break;
case 189 :
val = "-" ;
calCulate(val);
break;
case 190 :
val = "." ;
calCulate(val);
break;
case 191 :
val = "/" ;
calCulate(val);
break;
case 13:
reCall();
num.value = eval(num.value);
}
// 历史按键处理
/*
//数字按键区
if(Key == 48){
getVal(Key)
}
if(Key == 49){
getVal(Key)
}
if(Key == 50){
getVal(Key)
}
if(Key == 51){
getVal(Key)
}
if(Key == 52){
getVal(Key)
}
if(Key == 53){
getVal(Key)
}
if(Key == 54){
getVal(Key)
}
if(Key == 55){
getVal(Key)
}
if(Key == 56){
getVal(Key)
}
if(Key == 57){
getVal(Key)
}
//功能按键区
if(Key == 8){
delNum();
}
if(Key == 13){
val = "=" ;
calCulate(val);
}
if(Key == 107){
val = "+" ;
calCulate(val);
}
if(Key == 109){
val = "-" ;
calCulate(val);
}
if(Key == 110){
val = "." ;
calCulate(val);
}
if(Key == 111){
val = "/" ;
calCulate(val);
}
if(Key == 106){
val = "*" ;
calCulate(val);
}*/
});
function getVal(Key){
//
val = Key - 48;
//转入计算器封装函数
calCulate(val);
}
//定义一个历史回显功能
window.i = 0;
function showHistroyNum(){
//获取回显框
var lastShow = document.getElementById("lastShow");
var allLis = lastShow.children;
// 10.14 20:00 动态创建记录的遍历
if(lastNums.length >= allLis.length){
var li = document.createElement("li");
lastShow.appendChild(li);
allLis[i].innerText = lastNums[i];
i++;
}
}
// 10.14 18:00 动态创建记录的遍历
/*
for(var i = 0 ; i< lastNums.length; i++){
var li = document.createElement("li");
lastShow.appendChild(li);
allLis[i].innerText = lastNums[i];
}*/
//定义一个回显框点击返回事件
$(function () {
var num = document.getElementById("screen");
$("#lastShow").delegate("li","click", function () {
num.value = this.innerText;
})
});
</script>
<style type="text/css">
body{
font-size:12px;
font-family:"微软雅黑";
color:#666;
}
*{
padding:0px;
margin:0px;
}
#cac{
width:830px;
height:500px;
background:#f2f2f2;
padding:10px;
margin: 0 auto;
}
#cac .c_show #screen{
width:810px;
height:42px;
border:none;
line-height:42px;
text-align:right;
padding-right:20px;
font-size:34px;
color:#9e9e9e;
}
#cac h2{
font-size:16px;
color:#000;
font-weight:500;
padding:12px 0 12px 20px;
cursor:move;
text-align: center;
}
#cac .c_key {
border:3px solid #fff;
overflow:auto;
margin:10px auto;
}
#cac .c_key input[type=button]{
float:left;
width:140px;
height:65px;
background:#eaeaea;
margin:11px;
text-align:center;
line-height:65px;
font-size:32px;
cursor:pointer;
list-style:none;
border:1px solid #fff;
transition: all 200ms;
}
#cac .c_key input[type=button]:hover{
background:#fff;
color:#000;
}
#equ{
width: 37% !important;
}
#back{
width: 37% !important;
}
#lastShow{
width: 100%;
height: 100px;
overflow: scroll;
}
#lastShow li{
text-align: center;
font-size: 20px;
border-bottom:1px solid #cccccc;
cursor: pointer;
line-height: 20px;
height: 20px;
width: 100%;
}
/*小屏幕768px以下的自适应*/
@media screen and (max-width: 768px){
#cac{
width:280px;
height:350px;
background: #a18652;
padding:10px;
margin: 50px auto;
}
#cac .c_show #screen{
width:270px;
height:42px;
border:none;
line-height:42px;
text-align:right;
padding-right:10px;
font-size:34px;
color:#9e9e9e;
}
#cac .c_key{
border:3px solid #fff;
overflow:auto;
margin:10px auto;
}
#cac .c_key input[type=button]{
border-radius: 10px;
float:left;
width:52px;
height:35px;
background: #d4a840;
margin:8px;
text-align:center;
line-height:40px;
font-size:24px;
cursor:pointer;
list-style:none;
border:1px solid rgba(0,0,0,0.1);
}
#equ{
width: 44% !important;
}
#back{
width: 43% !important;
}
}
</style>
<body>
<div id="cac">
<h2>计算器(可键盘控制)</h2>
<div class="c_show">
<input type="text" name="t" id="screen" value="" >
</div >
<div class="c_key">
<input type="button" value="1" onclick="calCulate(this.value)">
<input type="button" value="2" onclick="calCulate(this.value)">
<input type="button" value="3" onclick="calCulate(this.value)">
<input type="button" value="4" onclick="calCulate(this.value)">
<input type="button" value="5" onclick="calCulate(this.value)">
<input type="button" value="6" onclick="calCulate(this.value)">
<input type="button" value="7" onclick="calCulate(this.value)">
<input type="button" value="8" onclick="calCulate(this.value)">
<input type="button" value="9" onclick="calCulate(this.value)">
<input type="button" value="0" onclick="calCulate(this.value)">
<input type="button" value="." onclick="calCulate(this.value)">
<input type="button" value="C" onclick="calCulate(this.value)">
<input type="button" value="+" onclick="calCulate(this.value)">
<input type="button" value="-" onclick="calCulate(this.value)">
<input type="button" value="*" onclick="calCulate(this.value)">
<input type="button" value="/" onclick="calCulate(this.value)">
<input type="button" value="←" id="back" onclick="delNum()">
<input type="button" id="equ" value="=" onclick="calCulate(this.value)">
</div>
</div>
<h2 style="text-align: center;">历史回点区</h2>
<ul id="lastShow">
</ul>
</body>
</html>