“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

It is boring to always learn knowledge points, so do a small chestnut to relieve the fatigue of learning it (more tired)

I also talked about making a calculator in my learning small program video tutorial, but the calculator in the tutorial is so crude that I can only do some calculations. No, men need to be persistent.

Win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10, win10

Realized effect (the picture was not recorded completely, the right side is missing a bit) :



The text start

WeChat development documentation: developers.weixin.qq.com/miniprogram…


Create the page

In wechat small program, page is a very important concept. Calculator page can be generated by right-clicking in the resource manager to create a folder, or directly by entering the page address and name in the page object of app.json.

Here’s an example from app.json:

"pages": [
    "pages/Calculator/Calculator"."pages/index/index"."pages/logs/logs",].Copy the code

CTRL + S saves, and the Calculator page appears in Explorer

When the page is first created, it has only one line in WXML, so just delete it.

The navigationBarTitleText text and background color of the top title bar can be set in app.json or in the JS (Calculator.js) of the page

  • Set in app.json

  • The Calculator. Js set in
onLoad() {
   wx.setNavigationBarTitle({
        title: Empty City Machine by Calculator,
    })
    wx.setNavigationBarColor({
        frontColor: '#ffffff'.backgroundColor: '#C37D58',}}),Copy the code



The page layout

In this production, in order to adapt to different models, I use the size format is RPX. The model is iPhone6, so 1px == 2rpx, the CSS written px pixel size by 2

The overall page is divided into three large, background, screen, buttons

I used the image tag for the background, which is absolutely positioned at 100% size

On the screen, I wanted to make a toolbar, but I gave up for now

The screen is currently divided into a calculation bar and a result bar

The key interface is divided into three parts: one is the function of clearing, positive and negative numbers, and taking mod; one is the function of adding, subtracting, multiplying and dividing the five keys; the other is the part of the number keys

Here is:



The page style

The style of the page is concentrated in the WXSS file

The screen and buttons have a ground-glass effect, which blurs out the background image at the bottom

The ground-glass effect was made mainly by background-color translucent color, and then backdrop filter blur effect was set

The MDN for the Sydari-filter is developer.mozilla.org/zh-CN/docs/…

Here you can choose your own colors, such as my screen CSS:

background-color: rgba(255.255.255.3);  /* Background color */
box-shadow: 6rpx 6rpx 12px 6rpx rgba(0.0.0.3);  / * * / shadow
backdrop-filter: blur(20rpx);  /* Gaussian filter */
Copy the code

For the keyboard layout I used the Flex layout, which worked very well. I set the top keys to 25% wide and let flex-wrap: wrap; The wrap is in effect, and the keys are effectively laid out.

In setting up0 keysWhen using:nth-childYou can select the subclass

In the click of the keyboard keys, keys need to have a dynamic interaction process, in the micro channel small program has a concept of hover class, hover class can be attached to a class on the view, the class style is the style of the key pressed, usually after the finger raised, The duration of this style is 400 milliseconds, which can be set using hohover stay-time

By the way, even in WXSS, there is still :hover, but this time :hover is set to press down the style, and the finger does not recover oh



Data rendering

On the keyboard below the calculator, there are 19 keys, and it would be too tedious to write one key at a time into WXML, and it would be a hassle to write click methods

So I write the information about these buttons to a JS file. In Page(), there is data, which is the initial data set of the Page. In the keysData array object, there is an array of keys, each of which has name, index and type properties. The type attribute can be used to distinguish between an operator and a number

/** * page initial data */
data: {
   keysdata: [  // type: 0 operator 1 number
       { name: 'AC'.index: '001'.type: 0 },
       { name: '+ / -.index: '002'.type: 0 },
       { name: The '%'.index: '003'.type: 0 },
       { name: 'present'.index: '004'.type: 0 },
       { name: '7'.index: '005'.type: 1 },
       { name: '8'.index: '006'.type: 1 },
       { name: '9'.index: '007'.type: 1 },
       { name: The '*'.index: '008'.type: 0 },
       { name: '4'.index: '009'.type: 1 },
       { name: '5'.index: '0010'.type: 1 },
       { name: '6'.index: '0011'.type: 1 },
       { name: The '-'.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'./ / the result
   calNum1: ' '.// Calculate the front digit
   calNum2: ' '.// Calculate the back bit
   calIcon: ' './ / calculation
   calIconEQ: ' '.// = The operator
   isCompute: false.// Whether to calculate
   lastbtn: 0.// The previous button 0: number 1: calculate symbol 2: equal to 3: clear 4: positive or negative
},
Copy the code

The wX :for statement is used in the WXML key rendering to iterate through the rendered keys

<view class="keyboards" wx:for="{{ keysdata }}" wx:key="index">
    <view class="keys" data-num="{{ item }}" hover-class="hoverkeys"
    hover-stay-time="100" bindtap="keyClick" >
            {{ item.name }}
    </view>
</view>
Copy the code


Calculation logic

This is the most complicated and difficult part of the whole process

At first, I didn’t add the attributes of the previous button, which made my initial judgment tired and incomplete

And then I rewrote the logic

Compute (num1, num2, way) = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = Way and num1 and num2 may pass num1 and num2 as empty strings. So you need to calculate the value depending on the method (you don’t want to put code in there)

compute(num1, num2, way) {
    let res = 0;
    switch(way) {
        case The '%':
            if(! num1 && num1 ! =0) { num1 = '1' }
            if(! num2) { num2 ='1' }
            res = parseFloat(num1) % parseFloat(num2); break;
        case 'present':
            if(! num1) { num1 ='1' }
            if(! num2) { num2 ='1' }
            res = parseFloat(num1) / parseFloat(num2); break;
        case The '*': 
            if(! num1) { num1 ='1' }
            if(! num2) { num2 ='1' }
            res = parseFloat(num1) * parseFloat(num2); break;
        case The '-': 
            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;
}
Copy the code

CalNum1, calNum2, calIcon and other objects defined by data in the above data rendering are needed in the calculation procedure bar and the result bar

 <! -- Calculation process -->
 <view class="calcuProcess">
  {{ calNum1 }} {{ calIcon }} {{ calNum2 }} {{ calIconEQ }}
 </view>
 <! -- Results and inputs -->
 <view class="inputNum">
   {{ resultNum }}
 </view>
Copy the code

calNum1 calIcon calNum2 calInconEQ resultNum
7 + 8 = 15

Since keyboard keys are rendered using Wx :for, data-num=”{{item}}” uses data- to bind key data to the element

So you can use bindTap =”keyClick” to bind the keyClick method to determine which key is being pressed based on the target of the event

let n = event.target.dataset.num;

First determine whether the key is a numeric key or a compute key

If it is a numeric key and the last pressed key is a calculator, set the value of the input resultNum in the result field to an empty string first, and then check whether the first letter is 0. If it is a number such as 08 or 012, remove the 0 from the first letter

1. Each key has its own logical method, entering different methods based on the key value

// Determine which method to execute
switch (n.name) {
    case 'AC': this.clearScreen(); break;
    case '+ / -: this.isNegative(); break;
    case The '%': this.remainder(); break;
    case 'present': this.division(); break;
    case The '*': this.multiplication(); break;
    case The '-': this.reduce(); break;
    case '+': this.add(); break;
    case '=': this.equalRes(); break;
}        
Copy the code

The last button lastbTN is a number, then calNum1 is calculated with the current value displayed in the result column. For example: Let res = this.compute(data.calnum1, data.resultnum, ‘+’), calculate the data, then remove calNum2 and the last equal sign

If the procedure column is empty, press the operator directly, then it is

The difference between wechat applet and vue is that it is not two-way binding. Although using this.callcon = ‘some value’ can change the current calIncon, it does not change the WXML page. So you need to use the setData method to change the page

3, the current key value is equal sign to determine whether there is an equal sign in the calculation process column, if there is, then continue to calculate the value of calNum1 and the value of the result column as shown in the following example:

If calNum2 is not followed, determine if the last keystroke was a number or an equal sign


If the last key was a calculator

4. Clear character: set resultNum to 0, and set other symbols such as calNum1 to null


Note: here like the key of the logic is not specifically written, so you can diverge in writing, and my logic is not necessarily the optimal solution, can only say to you a general direction



The complete code

Calculator.wxml

<! -- Background -->
<image class="img" src=".. /.. /source/wei2.png"></image>
<! -- Screen part -->
<view class="calculateScreen">
  <! -- Function bar -->
  <view class="funBar"></view>
  <! -- Calculation process -->
  <view class="calcuProcess">
   {{ calNum1 }} {{ calIcon }} {{ calNum2 }} {{ calIconEQ }}
  </view>
  <! -- Results and inputs -->
  <view class="inputNum">
    {{ resultNum }}
  </view>  
</view>
<! -- Keyboard Interface -->
<view class="keyboard">
    <view class="keyboards" wx:for="{{ keysdata }}" wx:key="index">
        <view class="keys" data-num="{{ item }}" hover-class="hoverkeys"
        hover-stay-time="100" bindtap="keyClick" >
                {{ item.name }}
        </view>
    </view>
</view>
Copy the code

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;
  / * applet gaussian blur effect to add 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 (246245245, 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;
}
Copy the code

Calculator.js

// pages/Calculator/Calculator.js
Page({
    onLoad() {
        wx.setNavigationBarTitle({
            title: Empty City Machine by Calculator,
        })
        wx.setNavigationBarColor({
            frontColor: '#ffffff'.backgroundColor: '#C37D58',}}),/**
     * 页面的初始数据
     */
    data: {
        keysdata: [ // type: 0 operator 1 number
            { name: 'AC'.index: '001'.type: 0 },
            { name: '+ / -.index: '002'.type: 0 },
            { name: The '%'.index: '003'.type: 0 },
            { name: 'present'.index: '004'.type: 0 },
            { name: '7'.index: '005'.type: 1 },
            { name: '8'.index: '006'.type: 1 },
            { name: '9'.index: '007'.type: 1 },
            { name: The '*'.index: '008'.type: 0 },
            { name: '4'.index: '009'.type: 1 },
            { name: '5'.index: '0010'.type: 1 },
            { name: '6'.index: '0011'.type: 1 },
            { name: The '-'.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'./ / the result
        calNum1: ' '.// Calculate the front digit
        calNum2: ' '.// Calculate the back bit
        calIcon: ' './ / calculation
        calIconEQ: ' '.// = The operator
        isCompute: false.// Whether to calculate
        lastbtn: 0.// The previous button 0: number 1: calculate symbol 2: equal to 3: clear 4: positive or negative
    },

    // Keyboard click event
    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' ) {
                    // Whether it is equal to pass
                    if (this.data.calIconEQ) {
                        this.clearScreen();
                    }
                    this.data.resultNum = ' ';
                }
                this.data.resultNum += n.name;
            }
            
            this.setData({ resultNum: this.data.resultNum })
            this.data.lastbtn = 0;  // Update the latest by pressing the button
        } else if(n.type == 0) {// Determine which method to execute
            switch (n.name) {
                case 'AC': this.clearScreen(); break;
                case '+ / -: this.isNegative(); break;
                case The '%': this.remainder(); break;
                case 'present': this.division(); break;
                case The '*': this.multiplication(); break;
                case The '-': this.reduce(); break;
                case '+': this.add(); break;
                case '=': this.equalRes(); break; }}},/ / add
    add () {
        let data = this.data;
        if (data.lastbtn == 1 && data.calIcon == '+') return ;        
        // Last number
        if (data.lastbtn == 0) {
            let res = this.compute(data.calNum1, data.resultNum, '+')
            this.setData({ calNum1: res }) 
            this.setData({ resultNum: res }) 
        }
        // last time was equal to
        if (data.lastbtn == 2 && data.calIconEQ) {
            this.setData({ calNum1: data.resultNum }) 
            this.setData({ calNum2: ' ' })
            this.setData({ calIconEQ: ' '})}// If the interface is empty
        if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum });
        }
        this.setData({ calIcon: '+' });
        data.lastbtn = 1;  // Update the latest by pressing the button
    },
    / / remove
    clearScreen () {
        this.setData({ resultNum: '0' });
        this.setData({ calNum1: ' ' });
        this.setData({ calNum2: ' ' });
        this.setData({ calIcon: ' ' });
        this.setData({ calIconEQ: ' ' });
        this.data.lastbtn = 3;  // Update the latest by pressing the button
        console.clear()
    },
    / / plus or minus
    isNegative (){
        let data = this.data;
        data.resultNum = parseFloat(data.resultNum);  // The value is a string
        if (data.resultNum > 0) {this.setData({ resultNum: -data.resultNum }) 
        } else {
            this.setData({ resultNum: Math.abs(data.resultNum) }) 
        }
        data.lastbtn = 4;  // Update the latest by pressing the button
    },
    / / remainder
    remainder () {
        let data = this.data;
        if (data.lastbtn == 1 && data.calIcon == The '%') return ;
        // Last number
        if (data.lastbtn == 0) {
            if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum }) 
            } else {
                let res = this.compute(data.calNum1, data.resultNum, The '%')
                this.setData({ calNum1: res }) 
                this.setData({ resultNum: res }) 
            }
        }
        // last time was equal to
        if (data.lastbtn == 2 && data.calIconEQ) {
            this.setData({ calNum1: data.resultNum }) 
            this.setData({ calNum2: ' ' })
            this.setData({ calIconEQ: ' '})}// If the interface is empty
        if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum });
        }
        this.setData({ calIcon: The '%' });
        data.lastbtn = 1;  // Update the latest by pressing the button
    },
    / / division
    division () {
        let data = this.data;
        if (data.lastbtn == 1 && data.calIcon == 'present') return ;
        
        if (data.calIconEQ) {
            
        }
        // Last number
        if (data.lastbtn == 0) {
            if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum }) 
            } else {
                let res = this.compute(data.calNum1, data.resultNum, 'present')
                this.setData({ calNum1: res }) 
                this.setData({ resultNum: res }) 
            }
        }
        // last time was equal to
        if (data.lastbtn == 2 && data.calIconEQ) {
            this.setData({ calNum1: data.resultNum }) 
            this.setData({ calNum2: ' ' })
            this.setData({ calIconEQ: ' '})}// If the interface is empty
        if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum });
        }
        this.setData({ calIcon: 'present' });
        data.lastbtn = 1;  // Update the latest by pressing the button
    },
    / / the multiplication
    multiplication () {
        let data = this.data;
        if (data.lastbtn == 1 && data.calIcon == The '*') return ;
        // Last number
        if (data.lastbtn == 0) {
            let res = this.compute(data.calNum1, data.resultNum, The '*')
            this.setData({ calNum1: res }) 
            this.setData({ resultNum: res }) 
        }
        // last time was equal to
        if (data.lastbtn == 2 && data.calIconEQ) {
            this.setData({ calNum1: data.resultNum }) 
            this.setData({ calNum2: ' ' })
            this.setData({ calIconEQ: ' '})}// If the interface is empty
        if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum });
        }
        this.setData({ calIcon: The '*' });
        data.lastbtn = 1;  // Update the latest by pressing the button
    },
    / / subtraction
    reduce() {
        let data = this.data;
        if (data.lastbtn == 1 && data.calIcon == The '-') return ;
        // Last number
        if (data.lastbtn == 0) {
            if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum }) 
            } else {
                let res = this.compute(data.calNum1, data.resultNum, The '-')
                this.setData({ calNum1: res }) 
                this.setData({ resultNum: res }) 
            }
        }
        // last time was equal to
        if (data.lastbtn == 2 && data.calIconEQ) {
            this.setData({ calNum1: data.resultNum }) 
            this.setData({ calNum2: ' ' })
            this.setData({ calIconEQ: ' '})}// If the interface is empty
        if(! data.calNum1 && ! data.calIcon) {this.setData({ calNum1: data.resultNum });
        }
       
        this.setData({ calIcon: The '-' });
        data.lastbtn = 1;  // Update the latest by pressing the button
    },
    / / the result
    equalRes() {
        let data = this.data;
        let res;
        // Check whether it is equal to pass
        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 ;
            // Check whether the latter number exists
            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;  // Update the latest by pressing the button
    },
    compute(num1, num2, way) {
        let res = 0;
        switch(way) {
            case The '%':
                if(! num1 && num1 ! =0) { num1 = '1' }
                if(! num2) { num2 ='1' }
                res = parseFloat(num1) % parseFloat(num2); break;
            case 'present':
                if(! num1) { num1 ='1' }
                if(! num2) { num2 ='1' }
                res = parseFloat(num1) / parseFloat(num2); break;
            case The '*': 
                if(! num1) { num1 ='1' }
                if(! num2) { num2 ='1' }
                res = parseFloat(num1) * parseFloat(num2); break;
            case The '-': 
                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;
        }
        returnres; }})Copy the code