Github路径
计算器小程序
https://github.com/Wangguangha/Calculator.git
项目结构
新建一个页面compute用于开发计算器功能
主要功能
计算器主要功能模块分析
效果演示
程序实现
UI规则
基本的规则如下:
- 输入框和按钮框长度要一致
- 按钮要设置圆角和间隔
- 模仿苹果手机的按钮风格
/* pages/home/home.wxss */
page {
width: 100%;
height: 100%;
}
/* 输入框的简单样式 */
input {
margin: 10px 0;
padding: 40rpx;
border: 1px solid #ccc;
border-radius: 5px;
text-align: right;
height: 15%;
margin-bottom: 20rpx; /* 确保 input 和 button-grid 之间有间距 */
}
.containerBack {
width: 100%;
height: auto;
min-height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
}
/* 固定宽度 */
.fixedWidth {
flex: 0 0 auto;
}
/* 自适应宽度 */
.autoFullWidth {
flex: 1 1 auto;
}
.high {
background: white;
height: 253rpx;
color: #fff;
}
.low {
background: #f4f4f4;
display: flex;
flex-direction: column;
flex: 1; /* 让它占据剩余空间 */
padding: 20rpx;
font-size: 38px;
}
.button-grid {
display: flex;
flex-direction: column;
width: 100%; /* 调整为100%以适应容器宽度 */
}
.button-row {
display: flex;
justify-content: space-between;
margin-bottom: 10rpx;
}
.grid-button {
width: 100rpx;
height: 100rpx;
background-color: gray;
color: black;
border: none;
border-radius: 5rpx;
font-size: 28rpx;
text-align: center;
line-height: 100rpx;
margin-right: 10rpx !important; /*强制属性*/
}
.button-row .grid-button:last-child {
margin-right: 0 !important; /* 最后一个按钮不需要右侧间距 */
}
.button-row:last-child .grid-button:first-child {
flex: 3; /* 第一个按钮占用两倍空间 */
}
.button-row:last-child .grid-button:not(:first-child) {
flex: 1; /* 其余按钮占用相同的空间 */
}
控件样式
<!--pages/home/home.wxml-->
<view class="containerBack">
<view class="fixedWidth">
<view class="high">
</view>
</view>
<view class="autoFullWidth">
<view class="low">
<input type="number" auto-focus focus="{{focus}}" value="{{inputValue}}" title="res_show" bindinput="handleInput"/>
<view class="button-grid">
<view class="button-row">
<button class="grid-button" bindtap="handleACButtonTap" data-index="0">AC</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="1" data-value="-">+/-</button>
<button class="grid-button" bindtap="handleComputeButtonTap" data-index="2" data-value="5">%</button>
<button class="grid-button" bindtap="handleComputeButtonTap" data-index="3" data-value="4">÷</button>
</view>
<view class="button-row">
<button class="grid-button" bindtap="handleButtonTap" data-index="4" data-value="7">7</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="5" data-value="8">8</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="6" data-value="9">9</button>
<button class="grid-button" bindtap="handleComputeButtonTap" data-index="7" data-value="3">×</button>
</view>
<view class="button-row">
<button class="grid-button" bindtap="handleButtonTap" data-index="8" data-value="4">4</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="9" data-value="5">5</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="10" data-value="6">6</button>
<button class="grid-button" bindtap="handleComputeButtonTap" data-index="11" data-value="2">-</button>
</view>
<view class="button-row">
<button class="grid-button" bindtap="handleButtonTap" data-index="12" data-value="1">1</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="13" data-value="2">2</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="14" data-value="3">3</button>
<button class="grid-button" bindtap="handleComputeButtonTap" data-index="15" data-value="1">+</button>
</view>
<view class="button-row">
<button class="grid-button" bindtap="handleButtonTap" data-index="16" data-value="0">0</button>
<button class="grid-button" bindtap="handleButtonTap" data-index="17" data-value=".">.</button>
<button class="grid-button" bindtap="handleEqualButtonTap" data-index="19">=</button>
</view>
</view>
</view>
</view>
</view>
计算规则
// pages/home/home.js
Page({
/**
* 页面的初始数据
*/
data: {
inputValue: '', // 保存输入框的值
operatorCode: 0,
clearFlag: 0,
num1: 0.0,
num2: 0.0
},
inputChange(event) {
this.setData({
inputValue: event.detail.value // 更新 data 中的 inputValue
});
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/*
* 事件传参处理函数
*/
sayHi(e) {
console.log(e);
var msg=e.target.dataset.msg;
wx.showToast({
title: '你好'+msg,
})
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh(e) {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
handleInput(e) {
let value = this.validateNumber(e.detail.value)
this.setData({
inputValue: value
})
},
validateNumber(val) {
// 先移除非数字、小数点和负号的字符
let sanitizedValue = val.replace(/[^0-9.-]/g, '');
// 仅允许负号在开头,其他位置的负号将被移除
// 移除非法字符,确保负号只能在开头
if (sanitizedValue.charAt(0) === '-') {
sanitizedValue = '-' + sanitizedValue.slice(1).replace(/-/g, ''); // 确保负号只能在第一个字符
} else {
sanitizedValue = sanitizedValue.replace(/-/g, ''); // 移除非首位的负号
}
// 确保只保留第一个小数点,移除多余的小数点
sanitizedValue = sanitizedValue.replace(/(\..*)\./g, '$1');
//确保小数点前有至少一个数字,如果没有,则移除小数点
const decimalIndex = sanitizedValue.indexOf('.');
if (decimalIndex !== -1 && decimalIndex === 0) {
// 小数点出现在第一位(无数字在前),则移除小数点
sanitizedValue = sanitizedValue.replace('.', '');
} else if (decimalIndex !== -1 && sanitizedValue.charAt(decimalIndex - 1) === '-') {
// 小数点紧跟在负号后面(负号后没有数字),也移除小数点
sanitizedValue = sanitizedValue.replace('.', '');
}
return sanitizedValue;
},
handleButtonTap(e) {
if(this.data.clearFlag === 1){
this.setData({
inputValue: '',
clearFlag: 0
});
}
let index = e.currentTarget.dataset.index;
let value = e.currentTarget.dataset.value;
// 更新输入框的值
let newValue;
if (value === '-') {
if(this.data.inputValue.charAt(0) === '-'){
newValue = this.data.inputValue.replace('-', '');
}else{
newValue = value + this.data.inputValue;
}
} else {
newValue = this.data.inputValue + value;
}
this.setData({
inputValue: newValue
});
// 如果有手动绑定 input 事件处理函数,手动调用它
this.handleInput({ detail: { value: newValue } });
},
// 按钮响应:AC
handleACButtonTap(e) {
// 清空输入框内容
this.setData({
inputValue: '',
num1 : 0.0,
num2 : 0.0,
operatorCode : 0,
clearFlag: 0
});
},
// 按钮响应: +、-、*、/ 清空输入框内容
handleComputeButtonTap(e) {
this.data.num1 = parseFloat(this.data.inputValue);
// 清空输入框内容
this.setData({
clearFlag: 1
});
// 记录运算符类型
let opValue = e.currentTarget.dataset.value;
// 设置运算符并显示结果
this.setOperator(opValue);
},
// 按钮响应: = 输出运算结果
handleEqualButtonTap(e) {
this.data.num2 = parseFloat(this.data.inputValue); // 保存第二个数值
let result = 0.0;
let op = parseInt(this.data.operatorCode, 10);
// 根据运算符执行计算
switch (op) {
case 1: // 加法
result = this.data.num1 + this.data.num2;
break;
case 2: // 减法
result = this.data.num1 - this.data.num2;
break;
case 3: // 乘法
result = this.data.num1 * this.data.num2;
break;
case 4: // 除法
if (this.data.num2 !== 0) {
result = this.data.num1 / this.data.num2;
} else {
wx.showToast({
title: '除数不能为0',
icon: 'none'
});
return;
}
break;
case 5: // 取余
result = this.data.num1 % this.data.num2;
break;
default:
wx.showToast({
title: '无效操作符',
icon: 'none'
});
break;
}
// 显示计算结果,并清空操作符和第二个数值
let formattedResult = parseFloat(result.toFixed(4)); // 保留四位小数,并去掉多余的小数位
this.setData({
inputValue: formattedResult.toString(), // 转换为字符串
num1:0.0,
num2:0.0,
clearFlag: 0
});
},
setOperator(op) {
// 更新运算符状态
this.setData({
operatorCode : op
}, () => {
//这里的回调函数在 setData 完成后执行
});
},
// 获取当前运算符
getOperator() {
return this.data.operatorCode;
}
})