微信小程序之计算器

在日常生活中,计算器是人们广泛使用的工具,可以帮助我们快速且方便地计算金额、成本、利润等。下面将会讲解如何开发一个“计算器”微信小程序。

一、开发思路

1、界面和功能

“计算器”微信小程序的页面效果如图所示

在计算器中可以进行整数和小数的加(+)、减(-)、乘(×)、除(÷)运算。“C”按钮为清除按钮,表示将输入的数字全部清空;“DEL”按钮为删除按钮,表示删除前面输入的一个数字;“+/-”按钮为正负号切换按钮,用于实现正负数切换;“.”按钮为小数点按钮,表示在计算过程中可以输入小数进行计算;“=”按钮为等号按钮,表示对输入的数字进行计算。

2、计算器设计数学原理

此计算器本本质是对数学表达式的求解,例如  Z=X+Y,其中,X,Y为两个自变量,Z为因变量,主要设计思路为千先输入X,Y,和"+"号,再输入“=”号计算结果并显示 。由此可知,基本操作为:

(1)输入第一个数字(存储为变量num1并显示)。

(2)输入运算符(存储为num2并显示)。

(3)输入运算符(形成表达式并显示)。

 (4)按下”=“(计算结果并显 示)。

3.  设计主要思路

根据以上分析可知,处理逻辑主要编写以下三个函数

        numBtn():处理函数三个数字按钮的事件处理函数

        opBtn:运算符按钮的事件处理函数

        execBtn():编写“=”按钮的事件处理函数

设计三个标识用以标识用户的三种状态,其中,数字改变标识为真:

numChangeFlag : 数字改变标识,第一数字和第二数字切换标识,初始值为false

execflag: 执行状态标识,初始值为false

resultflag: 结果状态标识,初始值为false

具体的处理逻辑详见四处理逻辑

二、界面设计

据以上的开发思路,界面分为显示区和按钮区,其中显示区又分为数字显示区、公式显示区两部分,上下排列;按钮可分为数字按钮,运算符按钮,功能按钮三部分,按钮显示区按四行四列显示,其中“0”独占两个单元格。代码如下所示:

<!--index.wxml-->
<navigation-bar title="计算器" back="{{false}}" color="black" background="#FFF"></navigation-bar>
<!--结果区域-->
<view class="result">
<view class="result-num">{{num}}</view>
<view class="result-sub">{{sub}}</view>
</view>
<!--按钮区域-->
<view class="btns">
<view>
<view hover-class="bg"  hover-stay-time="50"  bindtap="resetBtn">C</view>
<view hover-class="bg"  hover-stay-time="50"  bindtap="delBtn">DEL</view>
<view hover-class="bg"  hover-stay-time="50"  bindtap="negBtn">+/-</view>
<view hover-class="bg"  hover-stay-time="50"  bindtap="opBtn" data-val='×'>×</view>
</view>
<view>
    <view hover-class="bg" bindtap="numBtn" data-val="7">7</view>
    <view hover-class="bg" bindtap="numBtn" data-val="8">8</view>
    <view hover-class="bg" bindtap="numBtn" data-val="9">9</view>
    <view hover-class="bg" bindtap="opBtn" data-val="÷">÷</view>
  </view>
  <view>
    <view hover-class="bg" bindtap="numBtn" data-val="4">4</view>
    <view hover-class="bg" bindtap="numBtn" data-val="5">5</view>
    <view hover-class="bg" bindtap="numBtn" data-val="6">6</view>
    <view hover-class="bg" bindtap="opBtn" data-val="-">-</view>
  </view>
  <view>
    <view hover-class="bg" bindtap="numBtn" data-val="1">1</view>
    <view hover-class="bg" bindtap="numBtn" data-val="2">2</view>
    <view hover-class="bg" bindtap="numBtn" data-val="3">3</view>
    <view hover-class="bg" bindtap="opBtn" data-val="+">+</view>
  </view>
  <view>
    <view hover-class="bg" bindtap="numBtn" data-val="0">0</view>
    <view hover-class="bg" bindtap="dotBtn">.</view>
    <view hover-class="bg" bindtap="execBtn" data-val="=">=</view>
  </view>
</view>

界面布置总体上采用“flex”流式布局column方式,上下排列,按钮区以每四个按钮为一组,共分四组,同样采用flex的流式布局,具体css代码如下所示:

​
/**index.wxss**/
page {
  display: flex;
  flex-direction: column;
  height: 100vh;
  color: #555;
}
.result {
   flex: 1;
   background: #f3fef6;
   position: relative;
}
.result-num {
    position: absolute;
    font-size: 15vw;
    bottom: 5vh;
    right: 3vw;
}
.result-sub{
font-size: 10vw;
position: absolute;
bottom: 1vh;
right: 3vw;
}

.btns {
flex: 1;
}

/* 按钮样式 */
.bg {
background: #eee;
}
.btns {
flex: 1;
display: flex;
flex-direction: column;
font-size: 64rpx;
border-top: 1rpx solid #ccc;
border-left: 1rpx solid #ccc;
}
.btns > view {
flex: 1;
display: flex;
}
.btns > view > view {
flex-basis: 25%;
border-right: 1rpx solid #ccc;
border-bottom: 1rpx solid #ccc;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: center;
}
.btns > view:last-child > view:first-child {
flex-basis: 50%;
}

.btns > view:first-child > view:first-child {
color: #f00;
}

.btns > view > view:last-child {
color: #fc8e00;
}


​

三,知识储备

1、data-*自定义属性

data-*是微信小程序的自定义属性,由data-前缀加上自定义的属性名,自定义属性值表示要传递的数据 ,在事件处理函数中通过targert或currentTarget对象的datasett属性获取数据

2、模块

微信小程序提供了模块化开发的语法,,使用module.exports语法对外暴露接口,然后在需要使用模块的地方通过require()函数引入 模块。

四、处理逻辑

1、数学处理模块

模块代码如下:

​
// 精确计算
module.exports = {
    target: 'num1',  //表示当前正在输入哪个数字,取num1或num2
    num1: '0',
    num2: '0',
     op: '',
  // 重置
  reset() {
    this.num1 = '0'
    this.num2 = '0'
    this.target = 'num1'
    this.op = ''
  },
  changeNum2: function()
  {
     this.target='num2'
  },
  setNum: function(arg1){
     this[this.target]=arg1
  },
  getNum: function(){
      return this[this.target]
  },
  add: function(arg1, arg2) {
    var r1, r2, m
    try {
      r1 = arg1.toString().split(".")[1].length
    } catch (e) {
      r1 = 0
    }
    try {
      r2 = arg2.toString().split(".")[1].length
    } catch (e) {
      r2 = 0
    }
    m = Math.pow(10, Math.max(r1, r2))
    return (arg1 * m + arg2 * m) / m
  },
  sub: function(arg1, arg2) {
    var r1, r2, m, n
    try {
      r1 = arg1.toString().split(".")[1].length
    } catch (e) {
      r1 = 0
    }
    try {
      r2 = arg2.toString().split(".")[1].length
    } catch (e) {
      r2 = 0
    }
    m = Math.pow(10, Math.max(r1, r2))
    //动态控制精度长度
    n = (r1 >= r2) ? r1 : r2
    return ((arg1 * m - arg2 * m) / m).toFixed(n)
  },
  mul: function(arg1, arg2) {
    var m = 0,
      s1 = arg1.toString(),
      s2 = arg2.toString()
    try {
      m += s1.split(".")[1].length
    } catch (e) {}
    try {
      m += s2.split(".")[1].length
    } catch (e) {}
    return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
  },
  div: function(arg1, arg2) {
    var t1 = 0,
      t2 = 0,
      r1, r2
    try {
      t1 = arg1.toString().split(".")[1].length
    } catch (e) {}
    try {
      t2 = arg2.toString().split(".")[1].length
    } catch (e) {}

    r1 = Number(arg1.toString().replace(".", ""))
    r2 = Number(arg2.toString().replace(".", ""))
    return (r1 / r2) * Math.pow(10, t2 - t1)
  },
  // 进行运算
  getResult() {
    let result = 0
    if (this.op === '+') {
      result = this.add(this.num1, this.num2)
    } else if (this.op === '-') {
      result = this.sub(this.num1, this.num2)
    } else if (this.op === '×') {
      result = this.mul(this.num1, this.num2)
    } else if (this.op === '÷') {
      result =this. div(this.num1, this.num2)
    }
    return result
  }
}

​

模块全局变量:

                target: 'num1',  //表示当前正在输入哪个数字,取num1或num2
                num1: '0',   //第一个操作数
                num2: '0',  //第二个操作数
                     op: '',  //操作符

模块函数:

        changeNum2():  //设置当前操作数为第二操作数

          setNum():    //设置操作数的值

         getNum():   //获取操作数的值

         getResult():  //获取计算结果

其它的 add,sub,mul,div分别为加、减、乘、除函数。

 2、计算器处理逻辑

// index.js
const calc = require('../../utils/calc.js')
Page({
   /**  页面的初始数据  */
  data: {
      num: '0',
      op:''
  },
  //设置变量标识
  numChangeFlag : false,
  execflag: false,
  resultflag: false,
  //数字按钮的事件处理函数
  numBtn: function(e) {
        //点击数字按钮,获取对应的数字,将其值赋给num 
         var  num=e.target.dataset.val
         if(this.resultflag){
              this.resetBtn()
         }
         if(this.numChangeFlag){
             this.numChangeFlag=false
             this.execflag=true
             this.data.num='0'
             calc.changeNum2()
         }
         //设置输入的数字
         calc.setNum(this.data.num=='0'? num  : this.data.num +num)
         //页面中显示数字
         this.setData({ num: calc.getNum() })
      },
  //运算符按钮处理函数
  opBtn: function(e){
         calc.op=e.target.dataset.val
         this.numChangeFlag=true
         //判断是否已输入第2个数字
         if(this.execflag){
              this.execflag=false
              //已经输入第2个数字,再判断是否有结果状态
              if(this.resultflag){
                  this.resultflag=false
              } else {
                  calc.num1=calc.getResult()
              }
         }

         this.setData({
              sub: calc.num1+' '+calc.op+' ',
              num: calc.num1
         }) 
      },
   //"="按钮事件处理函数
   execBtn: function(){
  //解决没有输入第2个数字,不能按=号问题
  if(this.numChangeFlag){
      this.numChangeFlag=false
      this.execflag=true
      calc.num2=this.data.num
  }
  //如果已经输入第2个数字,执行计算操作
     if(this.execflag){
         this.resultflag=true
         var result=calc.getResult()
         this.setData({
           sub: calc.num1+' '+calc.op+' '+calc.num2+'=',
           num: result
         })
         calc.num1=result
     }
   } ,
 //重置按钮事件处理函数
 resetBtn:function(){
       calc.reset()
       this.execflag=false
       this.numChangeFlag=false
       this.resultflag=false
       this.setData({
              sub: '',
              num: '0'
       })
 },
 //小数点按钮事件
 dotBtn:function(){
     //如果是计算结果状态,则重置计算器
      if(this.resultflag){
          this.resetBtn()
      }
    //如果等待输入第2个数字且还没有输入第2个数字,设为‘0’
    if(this.numChangeFlag) {
          this.numChangeFlag=false
          calc.setNum('0.')
    } else if(this.data.num.indexOf('.')<0){
       //如果当前数字没有".",需要加上"."
       calc.setNum(this.data.num+'.')
    }
    this.setData({
          num: calc.getNum(),          
    })
 },
 //删除按钮事件处理函数
 delBtn:function(){
    //如果当前是计算结果状态,则重置计算器
     if(this.resultflag) {
        return this.resetBtn()
      }
      //非计算结果状态
      var num=this.data.num.substr(0,this.data.num.length-1)
      calc.setNum(num==='' || num==='-' || num==='-0.' ? '0' : num)   
      this.setData({
        num: calc.getNum()
      })
 },
//正负切换按钮事件处理函数
negBtn:function(){
      //如果是0,不加正负号
      if(this.data.num==='0' || this.data.num==='0.'){
             return 
      }
    //如果当前是计算结果状态,则重置计算器
    if(this.resultflag){
          this.resetBtn()
    } else if(this.data.num.indexOf('-')<0){
        //当前没有负号,加负号
        calc.setNum('-'+this.data.num)
    } else {
      //当前有负号,去掉负号
      calc.setNum(this.data.num.substr(1))
    }
    this.setData({
      num: calc.getNum()
    })
},
})

 模块首先使用require()函数引入计算模块,其次是全局变量、事件处理函数,具体事件处理函数如下:

numBtn:数字键处理函数,具体逻辑如下:首先判断是否是结果状态,如果是结果状态则复位,否则判断是第二操作数状态,是则设置为第二操作数。最后,使用计算模块的setNum设置操作数,并使用setData进行双向绑定的数据显示。

execBtn:"="事件处理函数,此函数的主要作用是调用计算模块的getResult函数,获取计算结果,并使用setData进行双向绑定的数据显示。

其它的事件处理函数如代码所示,分别完成复位、小数点、删除等处理函数,处理逻辑请参照代码。

本文主要论述了微信小程序计算器的设置,从思路、界面、计算模块、处理逻辑等方面进行了详细的论述,并给出了源代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/870029.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

光猫设置桥接 路由器pppoe拨号 设置正常访问光猫 (openwrt)

网络信息展示 光猫桥接很简单吧&#xff0c;就不说了。先来列出修改前的网络接口和网络信息。 光猫192.168.1.1&#xff0c;openwrt 10.0.0.0/8 初始配置 需要记录的信息&#xff1a;WAN的网络设备&#xff08;eth1&#xff09;&#xff0c;光猫的IP&#xff08;192.168.1.1&am…

Qt中在pro中实现一些宏定义

在pro文件中利用 DEFINES 定义一些宏定义供工程整体使用。&#xff08;和在cpp/h文件文件中定义使用有点类似&#xff09;可以利用pro的中的宏定义实现一些全局的判断 pro中实现 #自定义一个变量 DEFINES "PI\"3.1415926\"" #自定义宏 DEFINES "T…

模拟电子技术-实验四 二极管电路仿真

实验四 二极管电路仿真 一&#xff0e;实验类型 验证性实验 二&#xff0e;实验目的 1、验证二极管的单向导电性 2、验证二极管的稳压特性。 三&#xff0e;实验原理 二极管的单向导电性&#xff1a; 四、实验内容 1、二极管参数测试仿真实验 1&#xff09;仪表仿真…

【MetaGPT系列】【MetaGPT完全实践宝典——多智能体实践】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、多智能体系统介绍2-4、多智能体案例分析2-4-1、构建智能体团队2-4-2、动作/行为 定义2-4-3、角色/智…

力扣141环形链表问题|快慢指针算法详细推理,判断链表是否有环|龟兔赛跑算法

做题链接 目录 前言&#xff1a; 一、算法推导&#xff1a; 1.假设有环并且一定会相遇&#xff0c;那么一定是在环内相遇&#xff0c;且是快指针追上慢指针。 2.有环就一定会相遇吗&#xff1f;快指针是每次跳两步&#xff0c;有没有可能把慢指针跳过去&#xff1f; 3.那一定…

算法第十五天:leetcode19.删除链表的倒数第N个节点

一、删除链表的倒数第N个节点的题目描述与链接 19.删除链表的倒数第N个节点的链接如下表所示&#xff0c;您可直接复制下面网址进入力扣学习&#xff0c;在观看下面的内容之前您一定要先做一遍哦&#xff0c;以便让我印象更深刻&#xff01;&#xff01;!https://leetcode.cn/p…

学习记录——day16 操作受限的线性表 链式栈

操作受限的线性表 1、在之前的内容&#xff0c;无论是顺序表还是链表&#xff0c;都是详细处理的线性表&#xff0c;既可以在端点处进行操作也 可以在中间位置操作 2、现实生活中&#xff0c;有很多并不需要在中间进行操作的序列&#xff0c;只在端点处进行操…

安宝特方案|解放双手,解决死角,AR带来质量监督新体验

AR质量监督 解放双手&#xff0c;解决死角 在当今制造业快速发展的背景下&#xff0c;质量监督成为确保产品高质量和完善的管理制度的关键环节。然而&#xff0c;传统的质量监督方式存在诸多挑战&#xff0c;如人工操作带来的效率低下、查岗不及时、摄像头死角等问题。 为了解…

wpf中轮询显示图片

本文的需求是&#xff0c;在一个文件夹中&#xff0c;放一堆图片的集合&#xff0c;然后在wpf程序中&#xff0c;按照定时的方式&#xff0c;循序显示照片。 全部代码 1.声明一个PictureInfo类 namespace WpfApp1 {public class PictureInfo{public string? FileName { get; …

OpenAI发布GPT-4 Mini的深度分析及中国大模型的弯道超车机会

引言 在OpenAI封禁中国IP访问其API后&#xff0c;紧接着推出了GPT-4 Mini&#xff0c;这是一个引发广泛关注和讨论的新举措。此举不仅让人们质疑OpenAI的战略方向&#xff0c;更引发了对中国大模型是否能弯道超车的讨论。本文将详细分析GPT-4 Mini的特点、市场影响及中国大模型…

Golang | Leetcode Golang题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; func hIndex(citations []int) int {n : len(citations)return n - sort.Search(n, func(x int) bool { return citations[x] > n-x }) }

如何在 SpringBoot 中优雅的做参数校验?

一、故事背景 关于参数合法性验证的重要性就不多说了&#xff0c;即使前端对参数做了基本验证&#xff0c;后端依然也需要进行验证&#xff0c;以防不合规的数据直接进入服务器&#xff0c;如果不对其进行拦截&#xff0c;严重的甚至会造成系统直接崩溃&#xff01; 本文结合…

算法学习笔记(8.8)-多重背包

目录 Question: 思路解析&#xff1a; 代码示例 多重背包的优化问题&#xff1a; 1.二进制优化 代码示例&#xff1a; 2.单调队列优化(滑动窗口) 代码示例 Question: 4. 多重背包问题 I - AcWing题库https://www.acwing.com/problem/content/description/4/ 多重背包简单来说其…

嵌入式面试总结

直接I/O——绕过内核缓冲 Linux允许应用程序在执行文件I/O操作时绕过内核缓冲区&#xff0c;从用户空间直接传递数据到文件或磁盘设备。 在调用open()函数时&#xff0c;直接添加O_DIRECT标志。 某些应用程序的作用是测试磁盘设备的读写速率&#xff0c;那么就要保证read等操…

【计算机毕业设计】890社区宠物管理与服务系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Android APP 音视频(02)MediaProjection录屏与MediaCodec编码

说明&#xff1a; 此MediaProjection 录屏和编码实操主要针对Android12.0系统。通过MediaProjection获取屏幕数据&#xff0c;将数据通过mediacodec编码输出H264码流&#xff08;使用ffmpeg播放&#xff09;&#xff0c;存储到sd卡上。 1 MediaProjection录屏与编码简介 这里…

Minos 多主机分布式 docker-compose 集群部署

参考 docker-compose搭建多主机分布式minio - 会bk的鱼 - 博客园 (cnblogs.com) 【运维】docker-compose安装minio集群-CSDN博客 Minio 是个基于 Golang 编写的开源对象存储套件&#xff0c;虽然轻量&#xff0c;却拥有着不错的性能 中文地址&#xff1a;MinIO | 用于AI的S3 …

【odoo17 | Owl】前端js钩子调用列表选择视图

概要 在我们选择多对一或者多对多字段的时候&#xff0c;经常看到可以弹出列表弹窗让人一目了然的效果&#xff0c;效果如下&#xff1a; 那么&#xff0c;这种效果是odoo本身封装好的组件&#xff0c;我们在平时的前端界面开发的时候&#xff0c;既不是后端视图的情况下&#…

Apache ShardingSphere Proxy5.5.0实现MySQL分库分表与读写分离

1. 前提准备 1.1 主机IP:192.168.186.77 version: 3.8services:mysql-master:image: mysql:latestcontainer_name: mysql-masterenvironment:MYSQL_ROOT_PASSWORD: 123456MYSQL_USER: masterMYSQL_PASSWORD: 123456MYSQL_DATABASE: db1 ports:- "3306:3306&quo…

SearchGPT 搜索引擎发布:让信息检索变得简单

如今的互联网时代&#xff0c;我们每天都在与海量数据搏斗。无论是学习、工作还是生活&#xff0c;我们都需要快速准确地获取所需信息。然而&#xff0c;传统搜索引擎往往让人感到力不从心&#xff1a;关键词需要精准&#xff0c;结果泛滥成灾&#xff0c;有用信息如大海捞针。…