微信小程序学习之路04-简易的计算器
2017-01-12 20:21
621 查看
今天继续玩一些微信小程序的api来做例子,感觉自己可能创造力不很足,只能模仿着别人的例子来做一个自己的计算器了。老规矩,github源码地址我会附在文章末尾,供大家参考。用微信开发者工具新建的项目,index.wxss我也不去改了。只在index.wxml界面加一个到计算器页面的入口。index.js里面加入一个参数.
下面是index.wxml
然后是index.js
这里给大家附上一张丑丑的界面图。可以看到我这里是新建了cal这个文件夹,里面放上cal.js cal.wxml cal.wxss三个文件
记得在这里你新建好了一个wxml,你就需要在app.json去做页面的配置,不然你是访问不到的。所以下面放一下app.json(由于有历史功能,待会再加一遍)
cal.wxss里面的rpx也是第一次见,查了一下
rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
下面是cal.wxss文件,里面也没什么特别的,都是用的flex弹性布局,只是flex-direction的区别,附上文件cal.wxss
接下来是cal.wxml
好了重点来了,下面是index.js,这里面基本所有的逻辑我都是敲了注释的,有什么不懂的也可以在下面给我留言,csdn我还是看得很多,这里建议大家可以先复制下试试我的代码没问题的话,就自己手动敲一敲,分析下简单的js逻辑.
index.js
我们只需要去判断输入逻辑,计算的事情就交给rpn.js库来做,我们只需要传入一个像1+2-3 这种表达式给他,他就能给出结果,下面给出rpn.js,这个不需要自己看,放在utils下面就行了
最后是查看运算历史,我们用wx.setStorageSync(‘callogs’,this.data.logs);将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 下面我们就来做查看历史这个操作。
先放一张效果图
下面是history.wxss
然后是history.wxml,循这个有什么不懂的可以打开api看看,wx:key这个
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 中的输入内容, 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供
字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
最后是history.js
说一下这个
防入坑指南
1、千万不要用background-image或者使用background设置背景图片,开发工具里可以显示,真机不能显示,替换采用image标签
2、当真机中元素没有办法横向排列时,试着改变一下display为inline-block
3、页面没有办法铺满整个手机屏幕时,添加page{height;100%;}
4、wxss文件里的样式并不会覆盖,而是先声明的有效,后声明的无效
5、不要大量使用本地图片,小程序有规定大小,超过875kb无法预览
6、永远以真机效果为准,开发者工具预览和真机偏差样式方面有可能偏差很大
最后放下github源码下载地址 有什么问题欢饮大家留言指出。
下面是index.wxml
<view class="container"> <view bindtap="bindViewTap" class="userinfo"> <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </view> <view class="usermotto"> <!--<text class="user-motto">{{motto}}</text>--> <button type="default" size="{{defaultSize}}" plain="{{plain}}" hover-class="button-hover" disabled="{{disabled}}" bindtap="toCalc">{{motto}}</button> </view> </view>
然后是index.js
//index.js //获取应用实例 var app = getApp() Page({ data: { motto: '简易计算器', userInfo: {}, defaultSize:'default', disabled:false, iconType:'info_cycle' }, //事件处理函数 bindViewTap: function() { wx.navigateTo({ url: '../logs/logs' }) }, onLoad: function () { console.log('onLoad') var that = this //调用应用实例的方法获取全局数据 app.getUserInfo(function(userInfo){ //更新数据 that.setData({ userInfo:userInfo }) }) }, //到计算器界面 toCalc:function(){ wx.navigateTo({ url: '../cal/cal' }) } })
这里给大家附上一张丑丑的界面图。可以看到我这里是新建了cal这个文件夹,里面放上cal.js cal.wxml cal.wxss三个文件
记得在这里你新建好了一个wxml,你就需要在app.json去做页面的配置,不然你是访问不到的。所以下面放一下app.json(由于有历史功能,待会再加一遍)
{ "pages":[ "pages/index/index", "pages/logs/logs", "pages/cal/cal" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle":"black" } }
cal.wxss里面的rpx也是第一次见,查了一下
rpx单位是微信小程序中css的尺寸单位,rpx可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
下面是cal.wxss文件,里面也没什么特别的,都是用的flex弹性布局,只是flex-direction的区别,附上文件cal.wxss
.content { height: 100%; display: flex; flex-direction: column; align-items: center; background-color: #ccc; font-family: "Microsoft YaHei"; overflow-x: hidden; } .layout-top{ width: 100%; margin-bottom: 30rpx; } .layout-bottom{ width: 100%; } .screen { text-align: right; width: 100%; line-height: 260rpx; padding: 0 10rpx; font-weight: bold; font-size: 60px; box-sizing: border-box; border-top: 1px solid #fff; } .btnGroup { display: flex; flex-direction: row; flex: 1; width: 100%; height: 5rem; background-color: #fff; } .item { width:25%; display: flex; align-items: center; flex-direction: column; justify-content: center; margin-top: 1px; margin-right: 1px; } .item:active { background-color: #ff0000; } .zero{ width: 50%; } .orange { color: #fef4e9; background: #f78d1d; font-weight: bold; } .blue { color:#d9eef7; background-color: #0095cd; } .iconBtn{ display: flex; } .icon{ display: flex; align-items: center; width:100%; justify-content: center; }
接下来是cal.wxml
<view class="content"> <view class="layout-top"> <view class="screen"> {{screenData}} </view> </view> <view class="layout-bottom"> <view class="btnGroup"> <view class="item orange" bindtap="clickBtn" id="{{idc}}">С</view> <view class="item orange" bindtap="clickBtn" id="{{idb}}">←</view> <!--<view class="item orange" bindtap="clickBtn" id="{{idt}}">+/-</view>--> <view class="item orange iconBtn" bindtap="history"> <icon type="{{iconType}}" color="{{iconColor}}" class="icon" size="25"/> </view> <view class="item orange" bindtap="clickBtn" id="{{idadd}}">+</view> </view> <view class="btnGroup"> <view class="item blue" bindtap="clickBtn" id="{{id9}}">9</view> <view class="item blue" bindtap="clickBtn" id="{{id8}}">8</view> <view class="item blue" bindtap="clickBtn" id="{{id7}}">7</view> <view class="item orange" bindtap="clickBtn" id="{{idj}}">-</view> </view> <view class="btnGroup"> <view class="item blue" bindtap="clickBtn" id="{{id6}}">6</view> <view class="item blue" bindtap="clickBtn" id="{{id5}}">5</view> <view class="item blue" bindtap="clickBtn" id="{{id4}}">4</view> <view class="item orange" bindtap="clickBtn" id="{{idx}}">×</view> </view> <view class="btnGroup"> <view class="item blue" bindtap="clickBtn" id="{{id3}}">3</view> <view class="item blue" bindtap="clickBtn" id="{{id2}}">2</view> <view class="item blue" bindtap="clickBtn" id="{{id1}}">1</view> <view class="item orange" bindtap="clickBtn" id="{{iddiv}}">÷</view> </view> <view class="btnGroup"> <view class="item blue zero" bindtap="clickBtn" id="{{id0}}">0</view> <view class="item blue" bindtap="clickBtn" id="{{idd}}">.</view> <view class="item orange" bindtap="clickBtn" id="{{ide}}">=</view> </view> </view> </view>
好了重点来了,下面是index.js,这里面基本所有的逻辑我都是敲了注释的,有什么不懂的也可以在下面给我留言,csdn我还是看得很多,这里建议大家可以先复制下试试我的代码没问题的话,就自己手动敲一敲,分析下简单的js逻辑.
index.js
//获取应用实例 var rpn = require("../../utils/rpn.js"); var app = getApp() Page({ data:{ idb:"back", idc:"clear", idt:"toggle", idadd:"+", id9:"9", id8:"8", id7:"7", idj:"-", id6:"6", id5:"5", id4:"4", idx:"*", id3:"3", id2:"2", id1:"1", iddiv:"/", id0:"0", idd:".", ide:"=", screenData:"0", operaSymbo:{"+":"+","-":"-","*":"*","÷":"/",".":"."}, lastIsOperaSymbo:false, iconType:'waiting_circle', iconColor:'white', logs:[] }, onLoad:function(options){ // 页面初始化 options为页面跳转所带来的参数 }, onReady:function(){ // 页面渲染完成 }, onShow:function(){ // 页面显示 }, onHide:function(){ // 页面隐藏 }, onUnload:function(){ // 页面关闭 }, clickBtn:function(event){ //获取触发点击事件的标签的id var id=event.target.id if(id==this.data.idb){//退格← var data=this.data.screenData; if(data==0){ return ; } data=data.substring(0,data.length-1); //屏幕上不会显示东西了 if(data==""||data=="-"){//只剩下一个负号?不合理对吧 data=0; } this.setData({ 'screenData':data }); }else if(id==this.data.idc){//清屏 this.setData({ 'screenData':'0' }); }else if(id==this.data.idt){//加正负号,这里没有在界面上用,这一段可以不用看的 var data=this.data.screenData; //0不考虑正负号 if(data=="0"){ return ; } var firstWord=data.charAt(0); if(data=="-"){//第一个字母是负号,给他变成正 data=data.substr(1); }else{ data="-"+data; ///如果你真的看到了这里,真的没必要看这个else if,因为这个就是给第一个数取正负号的问题,这里又没有括号选择,贼鸡肋,所以界面上也就不放这个功能了。 } this.setData({ 'screenData':data }); }else if(id==this.data.ide){//等于= var data=this.data.screenData; if(data=="0"){ return ; } //eval是js中window的一个方法,而微信页面的脚本逻辑在是在JsCore中运行,JsCore是一个没有窗口对象的环境,所以不能再脚本中使用window,也无法在脚本中操作组件 //var result = eval(newData); //eval方法不能应,只能我们自己来写了 //不过我们可以调用rpn.js这个库,他已经为我们做好了 //判断最后一位如果是操作符,则不运算 //isNaN() 函数用于检查其参数是否是非数字值。 isNaN(123)返回false isNaN(wqwq)返回true var lastWord = data.charAt(data.length-1); if(isNaN(lastWord)){ return ; } var log=this.data.screenData; //获取rpn库运算结果 console.log(log); var calData=rpn.calCommonExp(log); this.data.logs.push(log+"="+calData); var allLogs = wx.getStorageSync('callogs') || []; allLogs.push(log+"="+calData); wx.setStorageSync('callogs',allLogs); this.setData({ 'screenData':calData+"" }); }else{//运算符和数字的问题 还有点 if(this.data.operaSymbo[id]){ //如果是符号+-*/ if(this.data.lastIsOperaSymbo){ //如果是最后一位是符号,就不能在收入符号 return; } } var sd=this.data.screenData; var data; //这个if else逻辑很简单 if(sd==0){ data=id; }else{ data=sd+id; } this.setData({ 'screenData':data }); ///置一下最后一位是否为运算符的标志位 if(this.data.operaSymbo[id]){ this.setData({"lastIsOperaSymbo":true}); }else{ this.setData({"lastIsOperaSymbo":false}); } } }, history:function(){ wx.navigateTo({ url: '../history/history' }) } })
我们只需要去判断输入逻辑,计算的事情就交给rpn.js库来做,我们只需要传入一个像1+2-3 这种表达式给他,他就能给出结果,下面给出rpn.js,这个不需要自己看,放在utils下面就行了
function isOperator(value) { var operatorString = '+-*/()×÷'; return operatorString.indexOf(value) > -1; } function getPrioraty(value) { if(value == '-' || value == '+') { return 1; } else if(value == '*' || value == '/' || value == '×' || value == '÷' ) { return 2; } else{ return 0; } } function prioraty(v1, v2) { return getPrioraty(v1) <= getPrioraty(v2); } function outputRpn(exp) { var inputStack = []; var outputStack = []; var outputQueue = []; var firstIsOperator = false; exp.replace(/\s/g,''); if(isOperator(exp[0])){ exp = exp.substring(1); firstIsOperator = true; } for(var i = 0, max = exp.length; i < max; i++) { if(!isOperator(exp[i]) && !isOperator(exp[i-1]) && (i != 0)) { inputStack[inputStack.length-1] = inputStack[inputStack.length-1] + exp[i] + ''; } else { inputStack.push(exp[i]); } } if(firstIsOperator) { inputStack[0] = -inputStack[0] } while(inputStack.length > 0) { var cur = inputStack.shift(); if(isOperator(cur)) { if (cur == '(') { outputStack.push(cur); } else if (cur == ')') { var po = outputStack.pop(); while(po != '(' && outputStack.length > 0) { outputQueue.push(po); po = outputStack.pop(); } } else { while(prioraty(cur,outputStack[outputStack.length - 1]) && outputStack.length > 0) { outputQueue.push(outputStack.pop()); } outputStack.push(cur) } } else { outputQueue.push(Number(cur)); } } if(outputStack.length > 0){ while (outputStack.length > 0) { outputQueue.push(outputStack.pop()); } } return outputQueue; } function calRpnExp(rpnArr) { var stack = []; for(var i = 0, max = rpnArr.length; i < max; i++) { if(!isOperator(rpnArr[i])) { stack.push(rpnArr[i]); } else { var num1 = stack.pop(); var num2 = stack.pop(); if(rpnArr[i] == '-') { var num = num2 - num1; } else if(rpnArr[i] == '+') { var num = num2 + num1; } else if(rpnArr[i] == '*' || rpnArr[i] == '×') { var num = num2 * num1; } else if(rpnArr[i] == '/' || rpnArr[i] == '÷') { var num = num2/num1; } stack.push(num); } } return stack[0]; } function calCommonExp(exp) { var rpnArr = outputRpn(exp); return calRpnExp(rpnArr) } module.exports = { isOperator: isOperator, getPrioraty: getPrioraty, outputRpn: outputRpn, calRpnExp: calRpnExp, calCommonExp: calCommonExp }
最后是查看运算历史,我们用wx.setStorageSync(‘callogs’,this.data.logs);将 data 存储在本地缓存中指定的 key 中,会覆盖掉原来该 key 对应的内容,这是一个同步接口。 下面我们就来做查看历史这个操作。
先放一张效果图
下面是history.wxss
page{ min-height:100%; height:100%; } .content{ height:100%; display:flex; flex-direction:column; align-items:center; box-sizing:border-box; position:relative; } .item{ width:90%; line-height:100rpx; margin-top:3rpx; margin-bottom:3rpx; border-radius:3px; color:#fef4e9; border:1px solid #da7c0c; background:#f78d1d; display:block; margin-right:auto; margin-left:auto; } .main-bg{ height:100%; width:100%; min-height:100%; position:absolute; top:0; left:0; z-index:-1; }
然后是history.wxml,循这个有什么不懂的可以打开api看看,wx:key这个
wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 中的输入内容, 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。
wx:key 的值以两种形式提供
字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。
如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。
<view class="content"> <image class="main-bg" src="../asserts/img/timg.jpg"></image> <block wx:for="{{callogs}}" wx:for-item="log" wx:key="*this"> <view class="item">{{log}}</view> </block> </view>
最后是history.js
Page({ data:{ callogs:[] }, onLoad:function(){ console.log(wx.getStorageSync('callogs')); this.setData({ callogs:wx.getStorageSync('callogs') }); } })
说一下这个
防入坑指南
1、千万不要用background-image或者使用background设置背景图片,开发工具里可以显示,真机不能显示,替换采用image标签
2、当真机中元素没有办法横向排列时,试着改变一下display为inline-block
3、页面没有办法铺满整个手机屏幕时,添加page{height;100%;}
4、wxss文件里的样式并不会覆盖,而是先声明的有效,后声明的无效
5、不要大量使用本地图片,小程序有规定大小,超过875kb无法预览
6、永远以真机效果为准,开发者工具预览和真机偏差样式方面有可能偏差很大
最后放下github源码下载地址 有什么问题欢饮大家留言指出。
相关文章推荐
- 微信小程序入门学习-- 简易Demo:计算器
- 微信小程序学习之路01-初识微信小程序
- 微信小程序小白开发学习之路———视图与渲染
- 微信小程序,学习笔记(三)微信小计算器
- 微信小程序学习之路(二) ------ 组件
- 微信小程序学习之路 在html中绑定点击事件
- Android学习之路——简易版微信为例(一)
- 微信小程序学习之路 扫一扫
- 微信小程序学习之路(一)
- iOS学习之路-04-一个简单的MVC模式的程序
- 微信小程序学习用demo:大写计算器;数字转换为大写
- 微信小程序开发小白学习之路--事件
- C# 简易版的计算器程序
- IOS学习之路二十(程序json转换数据的中文字符问题解决)
- 工程文件辉哥opencv学习之路【三】——opencv运行别人程序
- 【php学习之路】微信公众帐号
- EasyUi_学习之路_04
- window service 学习之路(四)【学习笔记】-- 调用外部EXE程序
- 嵌入式学习之路(四)——使用vi编写c程序
- 地球人己阻止不了程序猿们学习cocos2d-x了-学习笔记04