国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

基于AngularJS實現(xiàn)iOS8自帶的計算器

2019-11-20 09:01:47
字體:
供稿:網(wǎng)友

前言

首先創(chuàng)建angularjs的基本項目就不說了,最好是利用yeoman這個腳手架工具直接生成,如果沒有該環(huán)境的,當(dāng)然也可以通過自行下載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",".","="] }; });

這里的result是用來雙向綁定顯示運(yùn)算結(jié)果的,data為計算器鍵盤上的數(shù)字和符號。

該項目相關(guān)的所有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;}

然后是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>

這里class為history的p標(biāo)簽是用來顯示輸入記錄的,就是說你按下的所有鍵都會顯示在上面,便于查看結(jié)果,history為當(dāng)前scope下面的一個數(shù)組,后面會講解。這里使用一個textarea來作為計算結(jié)果的顯示屏幕,主要是為了使用雙向綁定的特性。同時生成計算器各個按鍵和界面元素都是通過對data對象進(jìn)行 循環(huán)遍歷來生成的,showClass方法是scope下面的一個方法,用來獲取不規(guī)則界面顯示元素的class屬性,后面會講解,showResult方法就是對按鍵響應(yīng)的主方法,我們所有對按鍵的按下響應(yīng)都是通過這個方法來的,后面會詳細(xì)講解。

showClass方法代碼如下:

  //顯示計算器樣式 $scope.showClass=function(index,a){  if(a==0){   return "zero";  }  return index==3||a=="="?"end-no":"normal"; };

這個方法主要是針對每行的最后一列要顯示為橘黃色和對于顯示0的按鍵要占用兩個單元格來進(jìn)行特殊處理。

到目前為止,已經(jīng)完全實現(xiàn)了計算器的界面

效果圖如下:

下面需要實現(xiàn)對按鍵的響應(yīng),按鍵包括數(shù)字鍵,運(yùn)算符鍵,AC鍵,每種按鍵按下都會有不同相應(yīng)并且按鍵之間是存在聯(lián)系的

為了使代碼容易講解,采用分段性給出showResult方法的代碼然后進(jìn)行詳細(xì)解釋的方法。

首先,這里要添加幾個變量進(jìn)行控制和存儲之用。

 //計算時用的數(shù)字的棧 $scope.num=[]; $scope.history=[];  //接受輸入用的運(yùn)算符棧 $scope.opt=[];  //計算器計算結(jié)果 $scope.result=""; //表示是否要重新開始顯示,為true表示不重新顯示,false表示要清空當(dāng)前輸出重新顯示數(shù)字 $scope.flag=true; //表示當(dāng)前是否可以再輸入運(yùn)算符,如果可以為true,否則為false $scope.isOpt=true;

num數(shù)組實際上是一個棧,用來接收用戶輸入的數(shù)字,具體用法后面會講解,history數(shù)組為用戶輸入的所有按鍵,每次按下就讓該按鍵上的符號或數(shù)字進(jìn)棧,然后使用綁定實時顯示在界面上。opt數(shù)組是另外一個棧,用來接收用戶輸入的運(yùn)算符。具體用法后面會講解,flag是一個標(biāo)志,為true的時候表示在按下數(shù)字的過程中被按下的數(shù)字是當(dāng)前顯示數(shù)字的一部分,需要跟在其后面顯示,比如當(dāng)前界面顯示的是12,再按下3的時候會判斷該標(biāo)志,如果為true,就顯示123,否則就清空界面,直接顯示3.isOpt是另外一個標(biāo)志,主要是為了防止用戶在輸入過程中對運(yùn)算符的非法輸入,比如說用戶接連輸入了1+2+,當(dāng)輸?shù)竭@里是,下面輸入的應(yīng)該是一個數(shù)字,但是用戶卻輸入了一個運(yùn)算符,通過判斷這個標(biāo)志,會讓計算器忽略這個非法的運(yùn)算符,讓輸入依然保持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;  //如果點擊的是個數(shù)字  if(reg.test(a)) {   //消除凍結(jié)   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;   }  }

init方法是用來初始化一些變量和標(biāo)志,讓它們回到原始狀態(tài)。showResult方法是顯示界面響應(yīng)用戶操作的主方法,上面的代碼是該方法中的一個if分支,表示如果輸入的是一個數(shù)字,那么如果對運(yùn)算符的輸入已經(jīng)被凍結(jié)(當(dāng)前不允許輸入運(yùn)算符了,輸入后會被忽略),那么輸入數(shù)字的時候,就解開凍結(jié)狀態(tài),以便下次輸入運(yùn)算符的時候會進(jìn)入運(yùn)算符棧。如果當(dāng)前顯示的結(jié)果不為空并且現(xiàn)在按下的數(shù)字是當(dāng)前顯示的數(shù)字的一部分并且沒有發(fā)生錯誤,那么顯示的結(jié)果就是當(dāng)前按下的數(shù)字接在當(dāng)前顯示數(shù)字的末尾,否則就代表重新顯示,重新顯示的時候需要讓下次再輸入的數(shù)字接在這個數(shù)字后面顯示。

js代碼(接上)

 //如果點擊的是AC  else if(a=="AC"){   $scope.result=0;   $scope.init();  }

如果點擊的是AC,那么代表初始化,讓顯示結(jié)果為0,清空所有狀態(tài)。

js代碼(接上)

 //如果點擊的是個小數(shù)點  else if(a=="."){   if($scope.result!=""&&!regDot.test($scope.result)){    $scope.result+=a;   }  }

如果點擊的是個小數(shù)點,則在當(dāng)前顯示不為空并且當(dāng)前顯示的結(jié)果里面不存在小數(shù)點的情況下讓這個小數(shù)點接在當(dāng)前顯示的末尾。

js代碼(接上)

 //如果點擊的是個取反操作符  else if(regAbs.test(a)){   if($scope.result>0){    $scope.result="-"+$scope.result;   }   else{    $scope.result=Math.abs($scope.result);   }  }

如果點擊的是個取反操作,則將當(dāng)前顯示結(jié)果取反

js代碼(接上)

 //如果點擊的是個百分號  else if(a=="%"){   $scope.result=$scope.format(Number($scope.result)/100);  }

如果點擊的是個百分號,則將當(dāng)前顯示結(jié)果除以100之后再顯示,這里有個format函數(shù)

其代碼如下:

 //格式化result輸出  $scope.format=function(num){  var regNum=/.{10,}/ig;   if(regNum.test(num)){    if(//./.test(num)){     return num.toExponential(3);    }    else{     return num.toExponential();    }   }   else{    return num;   }  }

它的作用主要是ios8自帶的計算器不會無限顯示很多位的數(shù)字,如果超過10位(包括小數(shù)點),則采用科學(xué)計算法來顯示,這里為了簡便,對于含有小數(shù)點且超過10位的顯示結(jié)果采用科學(xué)計算法計算的時候,讓它保留小數(shù)點之后3位顯示。

js代碼(showResult部分接上)

 //如果點擊的是個運(yùn)算符且當(dāng)前顯示結(jié)果不為空和error  else if($scope.checkOperator(a)&&$scope.result!=""&&$scope.result!="error"&&$scope.isOpt){   $scope.flag=false;   $scope.num.push($scope.result);   $scope.operation(a);   //點擊一次運(yùn)算符之后需要將再次點擊運(yùn)算符的情況忽略掉   $scope.isOpt=false;  }

這個分支是最復(fù)雜的一個分支,它代表如果輸入的是一個運(yùn)算符,那么就要進(jìn)行運(yùn)算了。進(jìn)入到這個分支,需要首先將flag置為false,作用是下次再輸入數(shù)字就是重新輸入數(shù)字而不是接著當(dāng)前顯示結(jié)果輸入了。

然后要讓當(dāng)前顯示的數(shù)字作為被運(yùn)算的數(shù)字首先進(jìn)入到數(shù)字棧中,operation方法就是運(yùn)算方法,因為這次已經(jīng)點擊了一個運(yùn)算符,所以下次再點擊就要忽略這個運(yùn)算符,將isOpt置為false。

operation代碼如下

  //比較當(dāng)前輸入的運(yùn)算符和運(yùn)算符棧棧頂運(yùn)算符的優(yōu)先級  //如果棧頂運(yùn)算符優(yōu)先級小,則將當(dāng)前運(yùn)算符進(jìn)棧,并且不計算,  //否則棧頂運(yùn)算符出棧,且數(shù)字棧連續(xù)出棧兩個元素,進(jìn)行計算  //然后將當(dāng)前運(yùn)算符進(jìn)棧。  $scope.operation=function(current){   //如果運(yùn)算符棧為空,直接將當(dāng)前運(yùn)算符入棧   if(!$scope.opt.length){    $scope.opt.push(current);    return;   }   var operator,right,left;   var lastOpt=$scope.opt[$scope.opt.length-1];   //如果當(dāng)前運(yùn)算符優(yōu)先級大于last運(yùn)算符,僅進(jìn)棧   if($scope.isPri(current,lastOpt)){    $scope.opt.push(current);   }   else{     operator=$scope.opt.pop();     right=$scope.num.pop();     left=$scope.num.pop();     $scope.calculate(left,operator,right);     $scope.operation(current);    }  };

該方法接受當(dāng)前輸入的運(yùn)算符作為參數(shù),其核心思想為,當(dāng)前接收到了一個運(yùn)算符,如果運(yùn)算符棧為空,則將當(dāng)前運(yùn)算符入棧,然后這種情況就不用再做什么了。如果當(dāng)前運(yùn)算符棧不為空,那么彈出當(dāng)前運(yùn)算符棧的棧頂元素,讓當(dāng)前接收的運(yùn)算符和棧頂運(yùn)算符比較優(yōu)先級(乘除優(yōu)先級大于加減,同一優(yōu)先級的情況下棧頂運(yùn)算符優(yōu)先級較高,因為先入棧的)。isPri方法用來判斷優(yōu)先級的,接收兩個參數(shù),第一個為當(dāng)前接收的運(yùn)算符,第二個為出棧的棧頂運(yùn)算符,如果按照前面所說的規(guī)則,當(dāng)前運(yùn)算符的優(yōu)先級較高,那么就直接將這個運(yùn)算符入棧。如果當(dāng)前運(yùn)算符優(yōu)先級小于棧頂運(yùn)算符,那么就需要進(jìn)行計算并更改計算器的顯示了,將運(yùn)算數(shù)字棧棧頂兩個元素依次彈出,分別作為一次運(yùn)算的兩個運(yùn)算數(shù)字,然后彈出運(yùn)算符棧的棧頂元素,作為本次運(yùn)算的運(yùn)算符,調(diào)用calculate方法進(jìn)行運(yùn)算

該方法代碼如下

 //負(fù)責(zé)計算結(jié)果函數(shù)  $scope.calculate=function(left,operator,right) {   switch (operator) {    case "+":     $scope.result = $scope.format(Number(left) + Number(right));     $scope.num.push($scope.result);     break;    case "-":     $scope.result = $scope.format(Number(left) - Number(right));     $scope.num.push($scope.result);     break;    case "×":     $scope.result = $scope.format(Number(left) * Number(right));     $scope.num.push($scope.result);     break;    case "÷":     if(right==0){      $scope.result="error";      $scope.init();     }     else{      $scope.result = $scope.format(Number(left) / Number(right));      $scope.num.push($scope.result);     }     break;    default:break;   }  };

該方法接受三個參數(shù),左運(yùn)算數(shù)字,中間的運(yùn)算符和右邊的運(yùn)算數(shù)字,按照加減乘除法運(yùn)算后更改result顯示結(jié)果并將計算結(jié)果入棧到運(yùn)算數(shù)字棧中,這里需要注意如果運(yùn)算的是除法并且除數(shù)是0,則發(fā)生了錯誤,顯示錯誤,清空所有狀態(tài),否則正常運(yùn)算。

一次運(yùn)算完成之后,運(yùn)算符棧和數(shù)字棧中的狀態(tài)都會被更改,而目前的按鍵current值還沒有入棧,所以又要重復(fù)上述過程進(jìn)行優(yōu)先級比較后在運(yùn)算,實際上是一個遞歸的過程,直到運(yùn)算符棧為空或者當(dāng)前運(yùn)算符的優(yōu)先級高于運(yùn)算符棧的棧頂運(yùn)算符。isPri方法是用來判斷運(yùn)算符優(yōu)先級的

代碼如下:

 //判斷當(dāng)前運(yùn)算符是否優(yōu)先級高于last,如果是返回true  //否則返回false  $scope.isPri=function(current,last){   if(current==last){    return false;   }   else {    if(current=="×"||current=="÷"){     if(last=="×"||last=="÷"){      return false;     }     else{      return true;     }    }    else{     return false;    }   }  };

判斷規(guī)則前面已經(jīng)講述。

此外還有一個checkOperator方法,是判斷輸入的符號是不是加減乘除四則運(yùn)算符號

代碼如下:

 //判斷當(dāng)前符號是否是可運(yùn)算符號  $scope.checkOperator=function(opt){   if(opt=="+"||opt=="-"||opt=="×"||opt=="÷"){    return true;   }   return false;  }

如果是就返回true,否則返回false。

到目前為止,還有一個輸入等于號的分支沒有

其代碼如下(接showResult方法)

 //如果點擊的是等于號  else if(a=="="&&$scope.result!=""&&$scope.result!="error"){   $scope.flag=false;   $scope.num.push($scope.result);   while($scope.opt.length!=0){    var operator=$scope.opt.pop();    var right=$scope.num.pop();    var left=$scope.num.pop();    $scope.calculate(left,operator,right);   }  } };

如果輸入的是等于號,則首先將flag置為false,允許下次輸入數(shù)字的時候界面重新顯示,并且要將當(dāng)前顯示的數(shù)字作為運(yùn)算數(shù)字入棧到數(shù)字棧。然后就要進(jìn)行不斷的出棧運(yùn)算直到運(yùn)算符棧為空才能夠停止。

總結(jié)

上面就是實現(xiàn)的主要代碼和過程,由于分支代碼較多而一次全部給出所有分支又不能夠詳細(xì)講述,所以將showResult方法分開了,可能看著不太適應(yīng)。由于寫的比較倉促且沒有花太多時間去測試,可能存在一些bug,歡迎指出。同時由于水平有限,可能該方法不是最好,歡迎給出更好的方案一起交流學(xué)習(xí)~~以上就是這篇文章的全部內(nèi)容了,希望對的大家的學(xué)習(xí)或者工作帶來一定的幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 宁明县| 敦化市| 阜康市| 寿宁县| 大足县| 改则县| 苏尼特右旗| 东山县| 九龙城区| 胶州市| 贡山| 泌阳县| 汝南县| 鄱阳县| 合肥市| 洛川县| 赤壁市| 辽阳市| 武胜县| 嘉义县| 金寨县| 全州县| 罗田县| 阿城市| 宁城县| 平南县| 平原县| 桂阳县| 昆明市| 灵山县| 明光市| 乌拉特中旗| 昌黎县| 弥勒县| 桂东县| 贞丰县| 陕西省| 静海县| 石河子市| 宜阳县| 察雅县|