前言
首先创建angularjs的基本项目就不说了,最好是利用yeoman这个脚手架工具直接生成,如果没有该环境的,当然也可以通过自行下载angularjs的文件引入项目。
实例详解
main.js是项目的主要js文件,所有的js都写在这个文件中,初始化之后,该文件的js代码如下
angular
.module('calculatorApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch'
])
.controller('MainCtrl', function ($scope) {
$scope.result="";
$scope.data={
"1":["AC","+/-","%","÷"],
"2":["7","8","9","×"],
"3":["4","5","6","-"],
"4":["1","2","3","+"],
"5":["0",".","="]
};
});
</div>
这里的result是用来双向绑定显示运算结果的,data为计算器键盘上的数字和符号。
该项目相关的所有css代码如下:
*{
margin:0;
padding:0;
}
body {
padding-top: 20px;
padding-bottom: 20px;
}
h1{
text-align:center;
color:#3385ff;
}
.main{
margin:20px auto;
border:1px solid #202020;
border-bottom: none;
width:60%;
height:600px;
}
.result{
display: block;
width: 100%;
height: 30%;
background:#202020;
box-sizing: border-box;
border:none;
padding: 0;
margin: 0;
resize: none;
color: #fff;
font-size: 80px;
text-align: right;
line-height: 270px;
overflow: hidden;
background-clip: border-box;
}
.row{
height: 14%;
background: #d7d8da;
box-sizing: border-box;
border-bottom: 1px solid #202020;
overflow: hidden;
}
.col{
height: 100%;
box-sizing: border-box;
border-right:1px solid #202020;
float: left;
color: #202020;
font-size: 28px;
text-align: center;
line-height: 83px;
}
.normal{
width: 25%;
}
.end-no{
width: 25%;
border-right: none;
background: #f78e11;
color: #fff;
}
.zero{
width: 50%;
}
.history{
background:#3385ff ;
color:#fff;
font-size: 22px;
text-align: center;
}
</div>
然后是html的布局如下:
<body ng-app="calculatorApp" >
<h1>calculator for ios8</h1>
<hr/>
<p class="history">{{ history.join(" ") }}</p>
<div class="main">
<textarea ng-model="result" class="result" ></textarea>
<div ng-repeat="item in data" class="row">
<div class="col" ng-repeat="a in item" ng-class="showClass($index,a)" ng-click="showResult(a)">{{ a }}</div>
</div>
</div>
</body>
</div>
这里class为history的p标签是用来显示输入记录的,就是说你按下的所有键都会显示在上面,便于查看结果,history为当前scope下面的一个数组,后面会讲解。这里使用一个textarea来作为计算结果的显示屏幕,主要是为了使用双向绑定的特性。同时生成计算器各个按键和界面元素都是通过对data对象进行 循环遍历来生成的,showClass方法是scope下面的一个方法,用来获取不规则界面显示元素的class属性,后面会讲解,showResult方法就是对按键响应的主方法,我们所有对按键的按下响应都是通过这个方法来的,后面会详细讲解。
showClass方法代码如下:
//显示计算器样式
$scope.showClass=function(index,a){
if(a==0){
return "zero";
}
return index==3||a=="="?"end-no":"normal";
};
</div>
这个方法主要是针对每行的最后一列要显示为橘黄色和对于显示0的按键要占用两个单元格来进行特殊处理。
到目前为止,已经完全实现了计算器的界面
效果图如下:

下面需要实现对按键的响应,按键包括数字键,运算符键,AC键,每种按键按下都会有不同相应并且按键之间是存在联系的
为了使代码容易讲解,采用分段性给出showResult方法的代码然后进行详细解释的方法。
首先,这里要添加几个变量进行控制和存储之用。
//计算时用的数字的栈 $scope.num=[]; $scope.history=[]; //接受输入用的运算符栈 $scope.opt=[]; //计算器计算结果 $scope.result=""; //表示是否要重新开始显示,为true表示不重新显示,false表示要清空当前输出重新显示数字 $scope.flag=true; //表示当前是否可以再输入运算符,如果可以为true,否则为false $scope.isOpt=true;</div>
num数组实际上是一个栈,用来接收用户输入的数字,具体用法后面会讲解,history数组为用户输入的所有按键,每次按下就让该按键上的符号或数字进栈,然后使用绑定实时显示在界面上。opt数组是另外一个栈,用来接收用户输入的运算符。具体用法后面会讲解,flag是一个标志,为true的时候表示在按下数字的过程中被按下的数字是当前显示数字的一部分,需要跟在其后面显示,比如当前界面显示的是12,再按下3的时候会判断该标志,如果为true,就显示123,否则就清空界面,直接显示3.isOpt是另外一个标志,主要是为了防止用户在输入过程中对运算符的非法输入,比如说用户接连输入了1+2+,当输到这里是,下面输入的应该是一个数字,但是用户却输入了一个运算符,通过判断这个标志,会让计算器忽略这个非法的运算符,让输入依然保持1+2+。
下面的代码分段给出,完整的代码就是将它们连接起来。
$scope.init=function(){
$scope.num=[];
$scope.opt=[];
$scope.history=[];
$scope.flag = true;
$scope.isOpt=true;
} ;
$scope.showResult=function(a){
$scope.history.push(a);
var reg=/\d/ig,regDot=/\./ig,regAbs=/\//ig;
//如果点击的是个数字
if(reg.test(a)) {
//消除冻结
if($scope.isOpt==false){
$scope.isOpt=true;
}
if ($scope.result != 0 && $scope.flag && $scope.result != "error") {
$scope.result += a;
}
else {
$scope.result = a;
$scope.flag = true;
}
}
</div>
init方法是用来初始化一些变量和标志,让它们回到原始状态。showResult方法是显示界面响应用户操作的主方法,上面的代码是该方法中的一个if分支,表示如果输入的是一个数字,那么如果对运算符的输入已经被冻结(当前不允许输入运算符了,输入后会被忽略),那么输入数字的时候,就解开冻结状态,以便下次输入运算符的时候会进入运算符栈。如果当前显示的结果不为空并且现在按下的数字是当前显示的数字的一部分并且没有发生错误,那么显示的结果就是当前按下的数字接在当前显示数字的末尾,否则就代表重新显示,重新显示的时候需要让下次再输入的数字接在这个数字后面显示。
js代码(接上)
//如果点击的是AC
else if(a=="AC"){
$scope.result=0;
$scope.init();
}
</div>
如果点击的是AC,那么代表初始化,让显示结果为0,清空所有状态。
js代码(接上)
//如果点击的是个小数点
else if(a=="."){
if($scope.result!=""&&!regDot.test($scope.result)){
$scope.result+=a;
}
}
</div>
如果点击的是个小数点,则在当前显示不为空并且当前显示的结果里面不存在小数点的情况下让这个小数点接在当前显示的末尾。
js代码(接上)
//如果点击的是个取反操作符
else if(regAbs.test(a)){
if($scope.result>0){
$scope.result="-"+$scope.result;
}
else{
$scope.result=Math.abs($scope.result);
}
}
</div>
如果点击的是个取反操作,则将当前显示结果取反
js代码(接上)
//如果点击的是个百分号
else if(a=="%"){
$scope.result=$scope.format(Number($scope.result)/100);
}
</div>
如果点击的是个百分号,则将当前显示结果除以100之后再显示,这里有个format函数
其代码如下:
//格式化result输出
$scope.format=function(num){
var regNum=/.{10,}/ig;
if(regNum.test(num)){
if(/\./.test(num)){
return num.toExp

