React计算器

React 实现一个计算器

需求分析:

  1. 鼠标点击数字和运算符,输入内容。
  2. 运算能力包括但不限于,加减乘除,取余。
  3. 能够清零,取消上一次错误的输入。

功能模块设计:

  1. 界面设计

  2. 获取数据显示

  3. 获取运算符进行相应计算

  4. 获取输出

  5. 清零

  6. 清除错误输入

开始

# 创建项目
create-react-app react-calculator

cd react-calculator

yarn start

具体实现

// Calculator.jsx
import React,{useState} from "react";

function Calculator(){
    // 指定input的初始值,进行双向绑定
    const [input_state, setInput_state] = useState('0');
    // 指定是否转换正负,是否已经选择运算符,是否选择小数点的状态
    const [rs,setRs] = useState({
        result:'0',
        ispm:false,
        isop:false,
        isdot:false,
    });
    // 遍历生成按钮
    const [btn_state] = useState([
        [7,8,9,'+/-','%'],
        [4,5,6,'+','-'],
        [1,2,3,'*','/'],
        [0,'.',' ','=','return']
    ]);

    // 单击非回退清空按钮事件
    const handleInput = (v)=>{
        let old_value = input_state;
        let new_value = v ;
        if(old_value!==''){
            setInput_state(actionType(old_value,new_value));
        }
    }
    // 检查按钮类型
    const actionType = (old_v,new_v) =>{
        let yun = ['+','-','*','/','%'];
        if(yun.indexOf(new_v) > -1){
            if(!rs.isop){
                setRs({...rs,isop:true,isdot:false});
                return old_v+' '+new_v+ ' ';
            }else{
                setRs({...rs,isdot:false});
                return old_v;
            }
        }else if(new_v==='='){
            if(!rs.isop){
                let temp = old_v.toString();
                if (temp.length===2&&temp.charAt(0)==='0'&&temp.charAt(1)==='.') {
                    old_v = '0';
                }
                // console.log(yun.indexOf(temp.charAt(temp.length-2)))
                if(temp.charAt(temp.length-1)==='.'&& temp.length > 2 && yun.indexOf(temp.charAt(temp.length-2)) === -1 ){
                    old_v = temp.substring(0,temp.length-1)+ '0';
                }
                if ((temp.charAt(temp.length-2)==='/'&&temp.charAt(temp.length-1)==='.')||(temp.charAt(temp.length-2)==='/'&&temp.charAt(temp.length-1)==='0')) {
                    old_v = '0';
                }
                console.log(old_v)
                let rs = eval(old_v);
                setRs({
                    result:rs,
                    ispm:false,
                    isop:false,
                    isdot:false,
                });
                return rs;
            }else{
                return old_v;
            }
        }else if(new_v==='+/-'){
            let flag = false;
            let arr = old_v.toString().split('');
            arr.forEach((item,index)=>{
                if(yun.indexOf(item) > -1 && index!==0){
                    flag = true;
                }
            })
            if(flag){
                return old_v;
            }
            if(!rs.ispm){
                setRs({...rs,ispm:true})
                return -old_v;
            }else{
                setRs({...rs,ispm:false})
                return -old_v;
            }
        }else if(new_v==='.'){
            if(!rs.isdot){
                setRs({...rs,isdot:true,isop:false})
                if(old_v===''){
                    return `0${new_v}`;
                }
                return old_v+new_v;
            }else{
                return old_v;
            }
        }else if(new_v==='return'){
            return rs.result;
        }else{
            let temp = old_v + new_v
            if (temp.length===2&&temp.charAt(0)==='0'&&temp.charAt(1)!=='.') {
                temp = temp.charAt(1);
            }
            if (rs.isop) {
                setRs({...rs,isop:false,isdot:false});
            }
            return temp;
        }
    }
    // 回退和重置
    const handleClick = v =>{
        if(v==='C'){
            setInput_state('0');
            setRs({
                result:'0',
                ispm:false,
                isop:false,
                isdot:false,
            });
        }else{
            let old_value = input_state;
            if(old_value!==''){//判断是否输入了数字
                old_value = old_value.substring(0,old_value.length-1);
                setInput_state(old_value);
                if(rs.isdot||rs.isop){
                    setRs({...rs,isop:false,isdot:false});
                }
            }
        }
    }

    return(
        <table>
            <thead>
                <tr>
                    <td colSpan="3" >
                        <input
                        // onKeyUp = {e=>{  
                        //     if(e.nativeEvent.keyCode === 13){ //e.nativeEvent获取原生的事件对像
                        //         handleInput('=')
                        // }}}
                        // onFocus={()=>setInput_state('')}
                        readOnly
                        onChange={e=>setInput_state(e.target.value)} 
                        value={input_state}
                        />
                    </td>
                    <td>
                        <button onClick = {()=>handleClick('C')} >C</button>
                    </td>
                    <td>
                        <button onClick = {()=>handleClick('CE')}>CE</button>
                    </td>
                </tr>
            </thead>
            <tbody>
                {btn_state.map(item=>{
                    return(
                    <tr key={item}>
                        {item.map(text =>(
                            <td key={text}> 
                                {text===' '?text:
                                <input
                                    type="button" 
                                    onClick={e=>handleInput(e.target.value)} 
                                    value={text}
                                />
                                } 
                            </td>
                        ))}
                    </tr>
                    )
                })}
            </tbody>
        </table>
    )
}

export default Calculator;

简单样式

table{
  padding: 20px;
  border: whitesmoke 1px solid;
}
tbody td input{
  width: 50px;
}
thead td input{
  width: 150px;
}
thead td button{
  width: 50px;
}

实现效果

ue52cT.png

总结

使用React Hooks 在一个函数式组件里进行状态的指定。

难点主要是判断一些输入的顺序问题。进行输入的合法性验证。(验证了一下,大部分应该是没有什么问题了。)

具体的计算可以更改方式,这里就直接使用了 eval(String s) 函数进行计算。

ps:取消了键盘输入算式的方式 : ) ,因为还要验证输入的合法性什么的。



奖励一下