制作一款好看的计算器

网友投稿 441 2022-05-28

微信小程序总是学习知识点也是很枯燥的,那么就做个小栗子来缓解一下学习的疲倦吧(更新累了)

像我学习小程序视频教程中也有说过做计算器,不过教程中的计算器太粗糙了,只能计算一下就结束了。 这可不行,男人要持久:dog:

所以我有感而发,准备做一个完整度高一些的简单计算器,计算器的基本功能就模仿win10自带的计算器吧,有加、减、乘、除、取余、正负这几块的功能,界面自己进行一下调整。

实现效果(图居然没录全,右侧少了一点):

正文开始

微信开发文档:https://developers.weixin.qq.com/miniprogram/dev/component/

创建页面

在微信小程序中,page页面是一个非常重要的概念,计算器页面可以在资源管理器中自己右键创建文件夹生成,也可以直接在app.json的page对象中输入页面地址和名称来生成。

app.json中例子如下:

"pages": [ "pages/Calculator/Calculator", "pages/index/index", "pages/logs/logs", ],

ctrl + s保存后,资源管理器中就出现了Calculator的页面

页面一开始创建出来,在wxml中只有一行字,直接删掉即可。

关于navigationBarTitleText顶部标题栏的文字和背景颜色,可以在app.json中设置,也可以在页面的JS(Calculator.js)中进行设置

在app.json中设置

Calculator.js中设置

onLoad() { wx.setNavigationBarTitle({ title: '空城机の计算器', }) wx.setNavigationBarColor({ frontColor: '#ffffff', backgroundColor: '#C37D58', }) },

页面布局

在本次制作当中,为了在不同机型下自适应,我使用的尺寸格式是rpx,机型选择了iPhone6,这样 1px == 2rpx,将CSS编写的px像素大小乘2即可

页面总体分为三大块,

背景、屏幕、按键

背景我使用了image标签来做的,绝对定位,大小100%

在屏幕上,本来我想制作一条工具栏,暂时先放弃了

屏幕上目前分为计算栏和结果栏

按键界面上分为三块,一块是清除、数字正负、取余功能,一块是加减乘除等于这5个按键,另一块是数字按键部分

图示:

页面样式

页面的样式主要集中在wxss文件当中

屏幕和按键都是以毛玻璃效果为主,这样可以将底部的背景图模糊的展现出来

毛玻璃效果的制作以背景色background-color半透明为主,然后设置backdrop-filter blur滤镜模糊效果

backdrop-filter的MDN:https://developer.mozilla.org/zh-CN/docs/Web/CSS/backdrop-filter

这里的颜色大家可以自己自由选择搭配,比如我的屏幕CSS:

background-color: rgba(255, 255, 255, .3); /* 背景色 */ box-shadow: 6rpx 6rpx 12px 6rpx rgba(0, 0, 0, .3); /* 阴影 */ backdrop-filter: blur(20rpx); /* 高斯滤镜 */

键盘的按键布局我使用了flex布局,这款布局非常好用,将上面的按键设置为宽25%,让flex-wrap: wrap;自动换行生效,按键就可以有效的排版布局了。

在设置0按键时,使用:nth-child子类选择即可

在点击键盘按键时,按键需要有一个动态的交互过程,在微信小程序中有一个hover-class的概念,在view上可以给hover-class附上一个class,这个class的样式就是按键按下时的样式,通常手指抬起后,这个样式的持续时间有400毫秒,这里可以使用hover-stay-time设置一个时间

顺便提一句,即使是在wxss中,依旧还是有:hover的存在,不过此时的:hover设置的就是按下去的样式,并且手指抬起不会恢复哦

数据渲染

在计算器下方的键盘上,按键有19个,如果一个按键一个按键写入wxml当中,就未免太过繁琐了,而且写点击方法时也比较麻烦

所以我将这些按钮的信息写入JS文件中,在Page()中存在data,这是页面的初始数据

设置keysdata数组对象,里面装了按键数组,每个按键都有name、index、type这三个属性。 type属性可以用来区分到底是计算符还是数字

/** * 页面的初始数据 */ data: { keysdata: [ // type:0 计算符 1 数字 { name: 'AC', index: '001', type: 0 }, { name: '+/-', index: '002', type: 0 }, { name: '%', index: '003', type: 0 }, { name: '÷', index: '004', type: 0 }, { name: '7', index: '005', type: 1 }, { name: '8', index: '006', type: 1 }, { name: '9', index: '007', type: 1 }, { name: '×', index: '008', type: 0 }, { name: '4', index: '009', type: 1 }, { name: '5', index: '0010', type: 1 }, { name: '6', index: '0011', type: 1 }, { name: '-', index: '0012', type: 0 }, { name: '1', index: '0013', type: 1 }, { name: '2', index: '0014', type: 1 }, { name: '3', index: '0015', type: 1 }, { name: '+', index: '0016', type: 0 }, { name: '0', index: '0017', type: 1 }, { name: '.', index: '0018', type: 1 }, { name: '=', index: '0019', type: 0 }, ], resultNum: '0', //结果 calNum1: '', // 计算前位 calNum2: '', // 计算后位 calIcon: '', // 计算符 calIconEQ: '', // = 计算符 isCompute: false, // 是否计算 lastbtn: 0, //上一个按钮 0:数字 1:计算符号 2:等于 3:清空 4:正负 },

在wxml的按键渲染中使用wx:for语句遍历渲染出按键

{{ item.name }}

计算逻辑

这是整个过程中最复杂最困难的部分

一开始我并没有添加记录上一个按键的属性,这导致了我一开始的判断做的很累,而且还不完善

然后又把逻辑给重新写了一下

在按键按下去的功能中,最重要的是计算和等于两种

计算中按键判断大致相同,首先先准备一个计算方法compute,根据传入参数将加减乘除取余这五种操作写入进去

compute(num1, num2, way)参数有三个,前两个代表计算的数值,way表示方式

并且num1和num2因为判断的不同,可能传入的num1,num2数值会是空字符串。所以需要将数值根据方法不同来进行计算 (本来不想放代码的)

compute(num1, num2, way) { let res = 0; switch(way) { case '%': if (!num1 && num1 != 0) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) % parseFloat(num2); break; case '÷': if (!num1) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) / parseFloat(num2); break; case '×': if (!num1) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) * parseFloat(num2); break; case '-': if (!num1) { num1 = '0' } if (!num2) { num2 = '0' } res = parseInt(num1) - parseInt(num2); break; case '+': if (!num1) { num1 = '0' } if (!num2) { num2 = '0' } res = parseFloat(num1) + parseFloat(num2); break; } return res; }

在计算过程栏和结果栏中需要用到上面数据渲染中data定义的calNum1、calNum2、calIcon等对象

{{ calNum1 }} {{ calIcon }} {{ calNum2 }} {{ calIconEQ }} {{ resultNum }}

因为键盘按键是使用wx:for进行渲染的,data-num="{{ item }}"利用data-将按键数据绑定到元素上

所以可以使用bindtap="keyClick"来绑定keyClick点击方法

根据event的target来判断当前按下的是哪一个按键

let n = event.target.dataset.num;

先判断按键是否为数字按键或者是计算符按键

如果是数字按键,如果上一次按下的按键是计算符,那么结果栏的输入显示的resultNum数值先置为空字符串,之后再判断首字母是否是0,如果是08、012这类数字,将首字母的0去掉

如果按下的是计算符按键,那么判断就更加复杂了

1、每一种按键都有自身的逻辑方法,根据按键值进入不同的方法

// 判断执行哪个方法 switch (n.name) { case 'AC': this.clearScreen(); break; case '+/-': this.isNegative(); break; case '%': this.remainder(); break; case '÷': this.division(); break; case '×': this.multiplication(); break; case '-': this.reduce(); break; case '+': this.add(); break; case '=': this.equalRes(); break; }

2、当前按键值是加减乘除这类计算值

上一次的按键lastbtn为数字,那么将calNum1和结果栏上当前显示的数值进行计算

比如:let res = this.compute(data.calNum1, data.resultNum, '+')

上一次按键为等号 = ,将数据计算出来,然后去除calNum2和最后的等号

如果计算过程栏为空,直接按计算符,那么就是

最后不要忘记改变上一次的按键lastbtn记录和calIcon计算符

微信小程序和vue的区别在于这不是双向绑定的,虽然使用this.callcon = '某个值'可以改变当前的calIncon,但是页面wxml上并不会改变,所以需要使用setData方法来进行改变页面

3、当前按键值是等于号

判断在计算过程栏中是否有过等于符,如果有,那么继续那calNum1的值和结果栏值进行计算

如下示例:

如果接下来没有calNum2,判断上一次按键是否是数字或者等于符

如果上一次按键是计算符

制作一款好看的计算器

4、清除符,将resultNum置为0,其他的calNum1等符号置为空即可

注意:这里像按键这些逻辑没有具体写,所以各位可以发散性的编写,并且我的逻辑并不一定是最优解,只能说给各位一个大致的方向

完整代码

Calculator.wxml

{{ calNum1 }} {{ calIcon }} {{ calNum2 }} {{ calIconEQ }} {{ resultNum }} {{ item.name }}

Calculator.wxss

/* pages/Calculator/Calculator.wxss */ .img{ position: absolute; top: 0rpx; width: 100%; height: 100vh; z-index: 0; } .calculateScreen { position: relative; width: 100%; height: 30vh; background-color: rgba(255, 255, 255, .3); z-index: 100; box-shadow: 6rpx 6rpx 12px 6rpx rgba(0, 0, 0, .3); overflow: hidden; /* 小程序的高斯模糊效果要加backdrop */ backdrop-filter: blur(20rpx); } .funBar { width: 100%; height: 90rpx; } .calcuProcess { width: 100%; height: 90rpx; line-height: 90rpx; font-size: 32rpx; text-align: right; color: #1d1a1a; } .inputNum { width: calc(100vw - 40rpx); height: calc(100% - 200rpx); line-height: 115rpx; font-size: 80rpx; text-align: right; padding: 0rpx 20rpx; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 5px 5px 5px #464443; } .keyboard { width: 100%; height: calc(70vh - 32rpx); padding-top: 12rpx; display: flex; flex-wrap: wrap; position: relative; } .keyboards { width: 25%; height: 20%; display: flex; justify-content:center; align-items: center; } .keys { width: 130rpx; height: 130rpx; border-radius: 50%; line-height: 130rpx; text-align: center; font-size: 60rpx; backdrop-filter: blur(10px); /* background-color: rgba(246,245,245, .6); */ background: linear-gradient(145deg, rgba(235,228,228, .3), rgba(221,214,214, .2)); box-shadow: 10px 10px 20px #8d8888, -10px -10px 20px #e2dfdf; color: #fff; text-shadow: 5px 5px 5px #992002; } .hoverkeys { background: linear-gradient(145deg, rgba(221,214,214, .6), rgba(235,228,228, .7)); box-shadow: 10px 10px 30px #302a2a, -10px -10px 30px #726060; } .keyboards:nth-child(17) { width: 50%; } .keyboards:nth-child(17) .keys { width: 300rpx; border-radius: 130rpx; }

Calculator.js

// pages/Calculator/Calculator.js Page({ onLoad() { wx.setNavigationBarTitle({ title: '空城机の计算器', }) wx.setNavigationBarColor({ frontColor: '#ffffff', backgroundColor: '#C37D58', }) }, /** * 页面的初始数据 */ data: { keysdata: [ // type:0 计算符 1 数字 { name: 'AC', index: '001', type: 0 }, { name: '+/-', index: '002', type: 0 }, { name: '%', index: '003', type: 0 }, { name: '÷', index: '004', type: 0 }, { name: '7', index: '005', type: 1 }, { name: '8', index: '006', type: 1 }, { name: '9', index: '007', type: 1 }, { name: '×', index: '008', type: 0 }, { name: '4', index: '009', type: 1 }, { name: '5', index: '0010', type: 1 }, { name: '6', index: '0011', type: 1 }, { name: '-', index: '0012', type: 0 }, { name: '1', index: '0013', type: 1 }, { name: '2', index: '0014', type: 1 }, { name: '3', index: '0015', type: 1 }, { name: '+', index: '0016', type: 0 }, { name: '0', index: '0017', type: 1 }, { name: '.', index: '0018', type: 1 }, { name: '=', index: '0019', type: 0 }, ], resultNum: '0', //结果 calNum1: '', // 计算前位 calNum2: '', // 计算后位 calIcon: '', // 计算符 calIconEQ: '', // = 计算符 isCompute: false, // 是否计算 lastbtn: 0, //上一个按钮 0:数字 1:计算符号 2:等于 3:清空 4:正负 }, // 键盘点击事件 keyClick(event) { let n = event.target.dataset.num; if (n.type == 1) { if (this.data.lastbtn == 1) { this.data.resultNum = '' } if (this.data.resultNum == '0') { if(n.name != '.') this.data.resultNum = n.name; else this.data.resultNum += n.name; } else { if( this.data.lastbtn == '2' ) { // 是否等于过 if (this.data.calIconEQ) { this.clearScreen(); } this.data.resultNum = ''; } this.data.resultNum += n.name; } this.setData({ resultNum: this.data.resultNum }) this.data.lastbtn = 0; //更新最新按下按钮 } else if(n.type == 0){ // 判断执行哪个方法 switch (n.name) { case 'AC': this.clearScreen(); break; case '+/-': this.isNegative(); break; case '%': this.remainder(); break; case '÷': this.division(); break; case '×': this.multiplication(); break; case '-': this.reduce(); break; case '+': this.add(); break; case '=': this.equalRes(); break; } } }, // 相加 add () { let data = this.data; if (data.lastbtn == 1 && data.calIcon == '+') return ; // 上一次数字 if (data.lastbtn == 0) { let res = this.compute(data.calNum1, data.resultNum, '+') this.setData({ calNum1: res }) this.setData({ resultNum: res }) } // 上一次等于 if (data.lastbtn == 2 && data.calIconEQ) { this.setData({ calNum1: data.resultNum }) this.setData({ calNum2: '' }) this.setData({ calIconEQ: '' }) } // 如果界面为空 if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }); } this.setData({ calIcon: '+' }); data.lastbtn = 1; //更新最新按下按钮 }, // 清除 clearScreen () { this.setData({ resultNum: '0' }); this.setData({ calNum1: '' }); this.setData({ calNum2: '' }); this.setData({ calIcon: '' }); this.setData({ calIconEQ: '' }); this.data.lastbtn = 3; //更新最新按下按钮 console.clear() }, // 正负 isNegative (){ let data = this.data; data.resultNum = parseFloat(data.resultNum); //数值变字符串 if (data.resultNum > 0){ this.setData({ resultNum: -data.resultNum }) } else { this.setData({ resultNum: Math.abs(data.resultNum) }) } data.lastbtn = 4; //更新最新按下按钮 }, // 余数 remainder () { let data = this.data; if (data.lastbtn == 1 && data.calIcon == '%') return ; // 上一次数字 if (data.lastbtn == 0) { if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }) } else { let res = this.compute(data.calNum1, data.resultNum, '%') this.setData({ calNum1: res }) this.setData({ resultNum: res }) } } // 上一次等于 if (data.lastbtn == 2 && data.calIconEQ) { this.setData({ calNum1: data.resultNum }) this.setData({ calNum2: '' }) this.setData({ calIconEQ: '' }) } // 如果界面为空 if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }); } this.setData({ calIcon: '%' }); data.lastbtn = 1; //更新最新按下按钮 }, // 除法 division () { let data = this.data; if (data.lastbtn == 1 && data.calIcon == '÷') return ; if (data.calIconEQ) { } // 上一次数字 if (data.lastbtn == 0) { if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }) } else { let res = this.compute(data.calNum1, data.resultNum, '÷') this.setData({ calNum1: res }) this.setData({ resultNum: res }) } } // 上一次等于 if (data.lastbtn == 2 && data.calIconEQ) { this.setData({ calNum1: data.resultNum }) this.setData({ calNum2: '' }) this.setData({ calIconEQ: '' }) } // 如果界面为空 if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }); } this.setData({ calIcon: '÷' }); data.lastbtn = 1; //更新最新按下按钮 }, // 乘法 multiplication () { let data = this.data; if (data.lastbtn == 1 && data.calIcon == '×') return ; // 上一次数字 if (data.lastbtn == 0) { let res = this.compute(data.calNum1, data.resultNum, '×') this.setData({ calNum1: res }) this.setData({ resultNum: res }) } // 上一次等于 if (data.lastbtn == 2 && data.calIconEQ) { this.setData({ calNum1: data.resultNum }) this.setData({ calNum2: '' }) this.setData({ calIconEQ: '' }) } // 如果界面为空 if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }); } this.setData({ calIcon: '×' }); data.lastbtn = 1; //更新最新按下按钮 }, // 减法 reduce() { let data = this.data; if (data.lastbtn == 1 && data.calIcon == '-') return ; // 上一次数字 if (data.lastbtn == 0) { if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }) } else { let res = this.compute(data.calNum1, data.resultNum, '-') this.setData({ calNum1: res }) this.setData({ resultNum: res }) } } // 上一次等于 if (data.lastbtn == 2 && data.calIconEQ) { this.setData({ calNum1: data.resultNum }) this.setData({ calNum2: '' }) this.setData({ calIconEQ: '' }) } // 如果界面为空 if (!data.calNum1 && !data.calIcon) { this.setData({ calNum1: data.resultNum }); } this.setData({ calIcon: '-' }); data.lastbtn = 1; //更新最新按下按钮 }, // 结果 equalRes() { let data = this.data; let res; // 判断是否等于过 if (data.calIconEQ) { res = this.compute(data.calNum1, data.calNum2, data.calIcon); this.setData({ calNum1: res }) this.setData({ resultNum: this.compute(res, data.calNum2, data.calIcon) }) } else { if (data.lastbtn == 2) return ; // 判断有没有后一个数 if (this.data.calNum2) {} else { if (data.lastbtn == 3) { this.setData({ calNum1: data.resultNum }) this.setData({ calIcon: '=' }); } if (data.lastbtn == 0 || data.lastbtn == 4) { if (data.calIcon && data.calIcon != '=') { res = this.compute(data.calNum1, data.resultNum, data.calIcon); this.setData({ calNum2: data.resultNum }); this.setData({ calIconEQ: '=' }); this.setData({ resultNum: res }); } else { this.setData({ calNum1: data.resultNum }) this.setData({ calIcon: '=' }); } } if (data.lastbtn == 1) { // console.log(data.resultNum) this.setData({ calNum1: data.resultNum }) res = this.compute(data.calNum1, data.resultNum, data.calIcon); this.setData({ calNum2: data.resultNum }) this.setData({ resultNum: res }) this.setData({ calIconEQ: '=' }); } } } data.lastbtn = 2; //更新最新按下按钮 }, compute(num1, num2, way) { let res = 0; switch(way) { case '%': if (!num1 && num1 != 0) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) % parseFloat(num2); break; case '÷': if (!num1) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) / parseFloat(num2); break; case '×': if (!num1) { num1 = '1' } if (!num2) { num2 = '1' } res = parseFloat(num1) * parseFloat(num2); break; case '-': if (!num1) { num1 = '0' } if (!num2) { num2 = '0' } res = parseInt(num1) - parseInt(num2); break; case '+': if (!num1) { num1 = '0' } if (!num2) { num2 = '0' } res = parseFloat(num1) + parseFloat(num2); break; } return res; } })

javaScript web前端 小程序

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Linux小项目-广告机项目设计
下一篇:通用型和垂直型SaaS
相关文章