React计算器
撰写时间: 2019-05-10 总共: 3593 字 转载请注明: BY-SA 4.0(除特别声明或转载文章外)
React 实现一个计算器
需求分析:
- 鼠标点击数字和运算符,输入内容。
- 运算能力包括但不限于,加减乘除,取余。
- 能够清零,取消上一次错误的输入。
功能模块设计:
-
界面设计
-
获取数据显示
-
获取运算符进行相应计算
-
获取输出
-
清零
-
清除错误输入
开始
# 创建项目
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;
}
实现效果
总结
使用React Hooks 在一个函数式组件里进行状态的指定。
难点主要是判断一些输入的顺序问题。进行输入的合法性验证。(验证了一下,大部分应该是没有什么问题了。)
具体的计算可以更改方式,这里就直接使用了 eval(String s) 函数进行计算。
ps:取消了键盘输入算式的方式 : ) ,因为还要验证输入的合法性什么的。