如何解决React Calculator:多点问题和方程问题
我已经在React中创建了可运行的计算器,但有两点需要弄清楚:
- 我想确保如果用户已经单击过一次,则不能输入第二个点
- 我希望方程式使用最后一个运算符(例如5 *-+ 5应该产生10的输出)
我仍然是一个初学者,所以我需要一个简单的代码来完成这些工作,而且我似乎无法弄清楚。非常感谢!这是到目前为止我的完整代码和Codepen链接:https://codepen.io/JuliaAyres/pen/dyXGvbO
class App extends React.Component {
constructor(props){
super(props);
this.state = {
display:'0'
}
this.changeValue = this.changeValue.bind(this);
this.equalEval = this.equalEval.bind(this);
}
changeValue(event){
if(event.target.value==='CE'){
this.setState({display: '0'});
}else{
this.setState({
display: (this.state.display==="0" ? event.target.value : this.state.display + event.target.value)
});
}
}
equalEval(){
this.setState({
display: eval(this.state.display)
});
}
render() {
return (
<div className="App">
<div className="calculator">
<div id="display">{this.state.display}</div>
<div className="buttongrid">
<button value="CE" id="clear" className="button" onClick={this.changeValue}>CE</button>
<button value=" / " id="divide" className="button" onClick={this.changeValue}>/</button>
<button value=" * " id="multiply" className="button" onClick={this.changeValue}>x</button>
<button value="7" id="seven" className="button" onClick={this.changeValue}>7</button>
<button value="8" id="eight" className="button" onClick={this.changeValue}>8</button>
<button value="9" id="nine" className="button" onClick={this.changeValue}>9</button>
<button value=" - " id="subtract" className="button" onClick={this.changeValue}>-</button>
<button value="4" id="four" className="button" onClick={this.changeValue}>4</button>
<button value="5" id="five" className="button" onClick={this.changeValue}>5</button>
<button value="6" id="six" className="button" onClick={this.changeValue}>6</button>
<button value=" + " id="add" className="button" onClick={this.changeValue}>+</button>
<button value="1" id="one" className="button" onClick={this.changeValue}>1</button>
<button value="2" id="two" className="button" onClick={this.changeValue}>2</button>
<button value="3" id="three" className="button" onClick={this.changeValue}>3</button>
<button value="." id="decimal" className="button" onClick={this.changeValue}>.</button>
<button value="0" id="zero" className="button" onClick={this.changeValue}>0</button>
<button value=" = " id="equals" className="button" onClick={this.equalEval}>=</button>
</div>
</div>
</div>
);
}
}
ReactDOM.render(<App />,document.getElementById('root'));
解决方法
对于十进制情况,我建议添加一个布尔状态(我们将其称为allowDecimal
)以启用或禁用最初设置为true
的十进制按钮。
然后在render()
内,将小数按钮的禁用属性设置为allowDecimal
的反面。原因是您想在allowDecimal
为假时禁用按钮:
<button value="." id="decimal" className="button" onClick={this.changeValue} disabled={!this.state.allowDecimal}>.</button>
然后在changeValue()
内,添加另一个if语句以检查event.target.value === '.'
。如果是,请将allowDecimal
状态设置为false
,这将禁用该按钮。您可以在用户按下等于或CE时再次将allowDecimal
设置回true
。希望这是有道理的。
解决起来很有趣,但是有一些问题(不幸的是,对初学者不太友好):
下面的代码利用以下Javascript方法/表达式:
1。)建议避免使用eval
,因为它可能unsafe且易碎。您可以使用math-expression-evaluator之类的库来处理字符串数学表达式。但是,即使那样,该库似乎也无法处理无效的表达式(例如1 + 1 +
),因此您必须try
和catch
任何错误。
let result;
try {
result = mexp.eval(this.state.display);
} catch (error) {
alert(error.message);
result = "NaN";
}
2。)当涉及小数时,您需要将字符串划分为字符串数组:"1.1 + 1.2" => ["1.1"," + ","1.2"]
。 为什么?因为您要确定数组中的最后一个值是否已经包含小数,以及如果再次按下小数按钮,是否要更新display
状态。
目前的情况是,必须手动检查每个按下的按钮值,并确定是否单击了allowDecimal
值高的按钮,并且您是否要切换此 +,-,*,/
状态如果已经存在小数,则必须确定是否更新此display
状态(这需要遍历整个display
字符串并找到最后一个 +,/
实例,然后确定是否最后一个值已经有一个小数了-您可以想象,这效率很低。)
相反,如果数组中的最后一个值已包含小数并且按下了小数按钮,则可以确定是否更新display
值:
/*
split string in array of strings by space(" ")
for example: "1.1 + 1.2" becomes ["1.1","1.2]
*/
const arrValue = prevState.display.split(" ");
/*
"lastValueHasDecimal" checks that the last value in the array doesn't contain
"." and that the current value of the button pressed is a decimal.
In short,if the last value already contains a decimal and the decimal button
was pressed,return the previous "display" state; otherwise,update the state.
str.indexOf("x") works by finding the index of "x" within a string
a value greater than -1 means "x" was found at an index within the string
for example: "1.2" has three indexes: [0,1,2] -- arrays start at index 0
and a decimal (".") can be found at index 1:
[
0: "1",1: ".",2: "2"
]
*/
const lastValueHasDecimal =
arrValue[arrValue.length - 1].indexOf(".") > -1 && value === ".";
3。)使用form
代替div
和button
。这使其对开发人员更加友好。使用表单时,按钮必须包含带有type
或button
的{{1}}属性!
演示
代码
App.js
submit
fields.js
import React from "react";
import mexp from "math-expression-evaluator";
import calculatorFields from "./fields";
import "./styles.css";
const initialState = {
display: "",result: ""
};
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = initialState;
this.changeValue = this.changeValue.bind(this);
this.resetDisplay = this.resetDisplay.bind(this);
this.equalEval = this.equalEval.bind(this);
}
changeValue({ target: { value } }) {
/*
setState accepts a function that accepts the current state as an argument
and expects a state object to be returned:
(prevState) => { return { ... } };
since you're checking whether or not the last value within "display"
has a decimal before updating the state,you'll want to conditionally update
the state with `value` based upon the "lastValueHasDecimal" expression.
if(lastValueHasDecimal) is true return prevState.display
else if false return prevState.display.concat(value)
prevState.display.concat(value)
is the same as:
prevState.display + value
*/
this.setState((prevState) => {
const arrValue = prevState.display.split(" ");
const lastValueHasDecimal =
arrValue[arrValue.length - 1].indexOf(".") > -1 && value === ".";
return {
display: lastValueHasDecimal
? prevState.display
: prevState.display.concat(value),result: ""
};
});
}
// if "CE" is pressed,return to "initialState" defined above
resetDisplay() {
this.setState(initialState);
}
// when the form is submitted...
equalEval(e) {
// prevent the page from refreshing,the "default" action of submitting a form
e.preventDefault();
// evaluate the "display" expression
let result;
try {
result = mexp.eval(this.state.display);
} catch (error) {
alert(error.message);
result = "NaN";
}
// update "result" with the result of evaluation
this.setState({ result });
}
render() {
const { display,result } = this.state;
return (
<div className="app">
<form onSubmit={this.equalEval} className="calculator">
<div id="display">
<input
className="result"
disabled
type="text"
value={!result ? display : result}
/>
</div>
<div className="buttongrid">
<button
type="button"
id="clear"
className="button"
onClick={this.resetDisplay}
>
CE
</button>
{calculatorFields.map(({ id,value }) => (
<button
key={id}
type="button"
value={value}
id={id}
className="button"
onClick={this.changeValue}
>
{value}
</button>
))}
<button
type="submit"
id="equals"
className="button"
disabled={!display}
>
=
</button>
</div>
</form>
</div>
);
}
}
如果没有任何意义,请随时提问。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。