练手:JS计算器(第一版)
本帖最后由 马黑黑 于 2023-12-31 09:29 编辑 <br /><br /><style>#ma {
margin: 50px auto 0;
padding: 8px;
width: fit-content;
max-width: 296px;
box-sizing: border-box;
height: fit-content;
border-radius: 10px;
background: #666;
box-shadow: 2px 4px 8px black;
}
#calcMsg, #calcRes {
padding: 6px;
color: #eee;
font-size: 14px;
word-break: break-all;
}
#calcRes {
text-align: right;
color: #000;
font-size: 20px;
background: #eee;
}
#calc {
display: grid;
place-items: center;
grid-template-columns: repeat(4, 70px);
grid-template-rows: repeat(5, 60px);
}
.btn, .clear {
width: 40px;
height: 40px;
border-radius: 50%;
background: #ccc;
box-shadow: inset 0 0 10px #000;
font: normal 20px/40px sans-serif;
text-align: center;
user-select: none;
}
.btn:hover, .clear:hover {
background: #aaa;
}
.num { color: darkred; font-weight: bold; }
</style>
<div id="ma">
<div id="calcMsg">计算器</div>
<div id="calcRes">0</div>
<div id="calc">
<div class="clear" id="clear">C</div>
<div class="btn" data-idx="(">(</div>
<div class="btn" data-idx=")">)</div>
<div class="clear" id="del">←</div>
<div class="btn num" data-idx="7">7</div>
<div class="btn num" data-idx="8">8</div>
<div class="btn num" data-idx="9">9</div>
<div class="btn" data-idx="/">÷</div>
<div class="btn num" data-idx="4">4</div>
<div class="btn num" data-idx="5">5</div>
<div class="btn num" data-idx="6">6</div>
<div class="btn" data-idx="*">×</div>
<div class="btn num" data-idx="1">1</div>
<div class="btn num" data-idx="2">2</div>
<div class="btn num" data-idx="3">3</div>
<div class="btn num" data-idx="-">-</div>
<div class="btn num" data-idx="0">0</div>
<div class="btn" data-idx=".">.</div>
<div class="btn" id="percent">%</div>
<div class="btn" data-idx="+">+</div>
<div class="clear" id="pow2">x²</div>
<div class="clear" id="pow3">x³</div>
<div class="clear" id="sqrt">√</div>
<div class="clear" id="equal" data-idx="=">=</div>
</div>
</div>
<script>
let btns = document.querySelectorAll('.btn');
let _eval = (fn) => new Function('return ' + fn)();
btns.forEach(item => {
item.onclick = () => {
calcRes.innerText = calcRes.innerText === '0' ? item.dataset.idx : (calcRes.innerText + item.dataset.idx);
calcMsg.innerText = calcRes.innerText;
}
});
clear.onclick = () => {
calcMsg.innerText = '计算器';
calcRes.innerText = '0';
};
equal.onclick = () => {
if(calcMsg.innerText.lastIndexOf('=') != -1) return;
let str = calcRes.innerText;
let result = _eval(str);
calcRes.innerText = num2Fixed(result);
calcMsg.innerText += '=';
};
del.onclick = () => {
calcRes.innerText = calcRes.innerText.slice(0,-1);
calcMsg.innerText = calcMsg.innerText.slice(0,-1);
};
sqrt.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.sqrt(num);
calcMsg.innerText = `√(${num})=`;
}
pow2.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.pow(num,2);
calcMsg.innerText = `${num}\u00b2=`;
}
pow3.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.pow(num,3);
calcMsg.innerText = `${num}\u00b3=`;
}
percent.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = _eval(num/100);
calcMsg.innerText = num + '/100=';
};
let num2Fixed = (res) => {
let str = typeof(res) === 'number' ? res.toString() : res;
let ar = str.split('.');
if(ar.length <= 1) return res;
if(ar.length >= 14) str = str.slice(0,-1);
return parseFloat(str);
};
</script> 本帖最后由 马黑黑 于 2023-12-31 09:30 编辑
代码
<style>
#ma {
margin: 50px auto 0;
padding: 8px;
width: fit-content;
max-width: 296px;
box-sizing: border-box;
height: fit-content;
border-radius: 10px;
background: #666;
box-shadow: 2px 4px 8px black;
}
#calcMsg, #calcRes {
padding: 6px;
color: #eee;
font-size: 14px;
word-break: break-all;
}
#calcRes {
text-align: right;
color: #000;
font-size: 20px;
background: #eee;
}
#calc {
display: grid;
place-items: center;
grid-template-columns: repeat(4, 70px);
grid-template-rows: repeat(5, 60px);
}
.btn, .clear {
width: 40px;
height: 40px;
border-radius: 50%;
background: #ccc;
box-shadow: inset 0 0 10px #000;
font: normal 20px/40px sans-serif;
text-align: center;
user-select: none;
}
.btn:hover, .clear:hover {
background: #aaa;
}
.num { color: darkred; font-weight: bold; }
</style>
<div id="ma">
<div id="calcMsg">计算器</div>
<div id="calcRes">0</div>
<div id="calc">
<div class="clear" id="clear">C</div>
<div class="btn" data-idx="(">(</div>
<div class="btn" data-idx=")">)</div>
<div class="clear" id="del">←</div>
<div class="btn num" data-idx="7">7</div>
<div class="btn num" data-idx="8">8</div>
<div class="btn num" data-idx="9">9</div>
<div class="btn" data-idx="/">÷</div>
<div class="btn num" data-idx="4">4</div>
<div class="btn num" data-idx="5">5</div>
<div class="btn num" data-idx="6">6</div>
<div class="btn" data-idx="*">×</div>
<div class="btn num" data-idx="1">1</div>
<div class="btn num" data-idx="2">2</div>
<div class="btn num" data-idx="3">3</div>
<div class="btn num" data-idx="-">-</div>
<div class="btn num" data-idx="0">0</div>
<div class="btn" data-idx=".">.</div>
<div class="btn" id="percent">%</div>
<div class="btn" data-idx="+">+</div>
<div class="clear" id="pow2">x²</div>
<div class="clear" id="pow3">x³</div>
<div class="clear" id="sqrt">√</div>
<div class="clear" id="equal" data-idx="=">=</div>
</div>
</div>
<script>
let btns = document.querySelectorAll('.btn');
let _eval = (fn) => new Function('return ' + fn)();
btns.forEach(item => {
item.onclick = () => {
calcRes.innerText = calcRes.innerText === '0' ? item.dataset.idx : (calcRes.innerText + item.dataset.idx);
calcMsg.innerText = calcRes.innerText;
}
});
clear.onclick = () => {
calcMsg.innerText = '计算器';
calcRes.innerText = '0';
};
equal.onclick = () => {
if(calcMsg.innerText.lastIndexOf('=') != -1) return;
let str = calcRes.innerText;
let result = _eval(str);
calcRes.innerText = num2Fixed(result);
calcMsg.innerText += '=';
};
del.onclick = () => {
calcRes.innerText = calcRes.innerText.slice(0,-1);
calcMsg.innerText = calcMsg.innerText.slice(0,-1);
};
sqrt.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.sqrt(num);
calcMsg.innerText = `√(${num})=`;
}
pow2.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.pow(num,2);
calcMsg.innerText = `${num}\u00b2=`;
}
pow3.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = Math.pow(num,3);
calcMsg.innerText = `${num}\u00b3=`;
}
percent.onclick = () => {
let num = calcRes.innerText;
calcRes.innerText = _eval(num/100);
calcMsg.innerText = num + '/100=';
};
let num2Fixed = (res) => {
let str = typeof(res) === 'number' ? res.toString() : res;
let ar = str.split('.');
if(ar.length <= 1) return res;
if(ar.length >= 14) str = str.slice(0,-1);
return parseFloat(str);
};
</script>
本帖最后由 马黑黑 于 2023-12-31 09:23 编辑
未解决的已知问题:
[*]浮点数运算的精准度。由于JS内部机制中基于浮点数的运算存在bug,我采用了截取方法处理这个问题,当小数点后面的数字大于等于14,去掉最后一位数,没有四舍五入,存在精度准确问题;
[*]特大整数运算未做测试,估计也可能存在问题,原因也是JS数据类型问题导致。不过JS会自动使用科学计数法,绝大多数的特大整数运算应该过得去;
[*]算式合法性检测机制。这个,比如四则运算的括号问题、除以0等问题,未做任何处理;
[*]0.xxx表达式的显示问题:小数点前面的 0 不显示。
作为练手小作品,第一版就酱吧。欢迎各位提出意见与建议,谢谢,顺祝2024新年快乐!
真好用,能下载到瘦机上吗? 能加上开平方,三角函数吗。 马黑黑 发表于 2023-12-31 08:51
代码
好制作!
评分后失效需刷新后恢复,或许是个例? 起个网名好难 发表于 2023-12-31 10:12
好制作!
评分后失效需刷新后恢复,或许是个例?
不是。JS代码如果包裹在 (function() { ... })(); 可以处理这个问题 樵歌 发表于 2023-12-31 10:06
能加上开平方,三角函数吗。
开方已经有了,其他三角函数运算是小问题 樵歌 发表于 2023-12-31 10:04
真好用,能下载到瘦机上吗?
手机上的计算器功能要比这个好 马黑黑 发表于 2023-12-31 10:28
不是。JS代码如果包裹在 (function() { ... })(); 可以处理这个问题
把let替换为var或许也能解决问题。 起个网名好难 发表于 2023-12-31 10:55
把let替换为var或许也能解决问题。
嗯,var有提升变量能力 这个好,不但能加加减减,还有平方和立方以及开平方和百分比,还能回到上一步。
功能还是很全面呢,用代码做出来的,太赞了{:4_199:} 版面设计也漂亮,给黑黑点赞{:4_199:} 马黑黑 发表于 2023-12-31 13:12
嗯,var有提升变量能力
let 不可以重复申明,只是为什么评分会导致重复申明。 起个网名好难 发表于 2023-12-31 15:40
let 不可以重复申明,只是为什么评分会导致重复申明。
评分后页面的刷新机制是局部刷新,重新加载一部分内容,包括帖子的主帖内容。所以,相应代码如果用立即执行函数包裹,这个问题多数会得到解决。 本帖最后由 起个网名好难 于 2024-1-2 09:51 编辑
马黑黑 发表于 2024-1-2 08:31
评分后页面的刷新机制是局部刷新,重新加载一部分内容,包括帖子的主帖内容。所以,相应代码如果用立即执 ...
ypPlayer 是不是与 js日历有冲突(见红影帖回家的路)事件处理都不响应了。 起个网名好难 发表于 2024-1-2 09:49
ypPlayer 是不是与 js日历有冲突(见红影帖回家的路)事件处理都不响应了。
这不是冲突问题,而是加载阻塞导致的 onclick 和 onchange 事件失效问题。一般可以考虑使用异步或延时来处理。
页:
[1]