diff --git a/css/iconfont.ttf b/css/iconfont.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..2f33db86a098f4c12eee19dacc3ae51b4dc677d5
Binary files /dev/null and b/css/iconfont.ttf differ
diff --git a/css/reset.css b/css/reset.css
new file mode 100644
index 0000000000000000000000000000000000000000..80ec8c001f9f7b8447712cd4c77ce9fb00c0fb03
--- /dev/null
+++ b/css/reset.css
@@ -0,0 +1,47 @@
+/* v2.0 | 20110126
+ http://meyerweb.com/eric/tools/css/reset/
+ License: none (public domain)
+*/
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
\ No newline at end of file
diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000000000000000000000000000000000000..c0b94cd308b14aa522c445d8e0d0650aa1eaa188
--- /dev/null
+++ b/css/style.css
@@ -0,0 +1,149 @@
+@font-face {
+ font-family: 'iconfont';
+ src: url('iconfont.ttf?t=1636334307125') format('truetype');
+}
+
+.display {
+ position: relative;
+ background-color: rgb(245, 245, 245);
+ height: 35.5vh;
+}
+
+#text {
+ position: absolute;
+ right: 20px;
+ bottom: 20px;
+ font-size: 30px;
+}
+
+.function {
+ width: 100%;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+
+/* 所有按键 */
+
+.function>* {
+ height: 9vh;
+ width: 16.4vw;
+ margin: 1.5vh 0 0 3vw;
+ border-radius: 2vw;
+ background-color: rgb(245, 245, 245);
+ text-align: center;
+ line-height: 9vh;
+ font-size: 26px;
+}
+
+.function>*:hover {
+ background-color: rgb(235, 235, 235);
+}
+
+.function>*:active {
+ background-color: rgb(205, 205, 205);
+}
+
+#sin,
+#sqrt,
+#pow,
+#pow2,
+#pi,
+#cos,
+#tan,
+#lg,
+#ln,
+#e {
+ color: rgb(99, 99, 99);
+}
+
+
+/* 功能键 */
+
+#clear,
+#divide,
+#multiply,
+#backspace,
+#minus,
+#plus {
+ background-color: rgb(233, 240, 255);
+ color: rgb(79, 118, 239);
+}
+
+#clear:hover,
+#divide:hover,
+#multiply:hover,
+#backspace:hover,
+#minus:hover,
+#plus:hover {
+ background-color: rgb(223, 230, 245);
+}
+
+#clear:active,
+#divide:active,
+#multiply:active,
+#backspace:active,
+#minus:active,
+#plus:active {
+ background-color: rgb(203, 210, 225);
+}
+
+
+/* 除清除以外的功能键 */
+
+#divide,
+#multiply,
+#backspace,
+#minus,
+#plus {
+ font-size: 36px;
+}
+
+
+/* 等号键 */
+
+#equals {
+ position: absolute;
+ right: 0;
+ top: 77.5vh;
+ right: 3vw;
+ height: 19.5vh;
+ line-height: 19.5vh;
+ font-size: 36px;
+ background-color: rgb(59, 131, 119);
+ color: rgb(253, 253, 253);
+}
+
+#equals:hover {
+ background-color: rgb(49, 121, 109);
+}
+
+#equals:active {
+ background-color: rgb(29, 101, 89);
+}
+
+
+/* 图标字体 */
+
+#sqrt,
+#backspace {
+ font-family: "iconfont" !important;
+ font-size: 26px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+#sqrt {
+ font-weight: bold;
+}
+
+
+/* 上标 */
+
+.function sup {
+ position: relative;
+ /* background-color: transparent; */
+ font-size: 16px;
+ bottom: 1.5vh;
+}
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..d7a79950aa387d13d96ce55e2446a6e4b4644db1
--- /dev/null
+++ b/index.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+ H5计算器
+
+
+
+
+
+
+
+
+
+
+
+
+
+
sin
+
+
xy
+
x2
+
π
+
cos
+
C
+
÷
+
×
+
+
tan
+
7
+
8
+
9
+
-
+
lg
+
4
+
5
+
6
+
+
+
ln
+
1
+
2
+
3
+
+
=
+
e
+
%
+
0
+
.
+
+
+
+
+
+
diff --git a/js/events.js b/js/events.js
new file mode 100644
index 0000000000000000000000000000000000000000..0600da05ee79421b23e127f1dcfac0690c21cc22
--- /dev/null
+++ b/js/events.js
@@ -0,0 +1,110 @@
+// 添加按键的响应事件
+window.onload = function() {
+ document.getElementById("sin").addEventListener('click', function() {
+ push("sin");
+ });
+ document.getElementById("sqrt").addEventListener('click', function() {
+ push("√");
+ });
+ document.getElementById("pow").addEventListener('click', function() {
+ push("^");
+ });
+ document.getElementById("pow2").addEventListener('click', function() {
+ push("^2");
+ });
+ document.getElementById("pi").addEventListener('click', function() {
+ push("π");
+ });
+ document.getElementById("cos").addEventListener('click', function() {
+ push("cos");
+ });
+ document.getElementById("divide").addEventListener('click', function() {
+ push("÷");
+ });
+ document.getElementById("multiply").addEventListener('click', function() {
+ push("×");
+ });
+ document.getElementById("tan").addEventListener('click', function() {
+ push("tan");
+ });
+ document.getElementById("num7").addEventListener('click', function() {
+ push("7");
+ });
+ document.getElementById("num8").addEventListener('click', function() {
+ push("8");
+ });
+ document.getElementById("num9").addEventListener('click', function() {
+ push("9");
+ });
+ document.getElementById("minus").addEventListener('click', function() {
+ push("-");
+ });
+ document.getElementById("lg").addEventListener('click', function() {
+ push("lg");
+ });
+ document.getElementById("num4").addEventListener('click', function() {
+ push("4");
+ });
+ document.getElementById("num5").addEventListener('click', function() {
+ push("5");
+ });
+ document.getElementById("num6").addEventListener('click', function() {
+ push("6");
+ });
+ document.getElementById("plus").addEventListener('click', function() {
+ push("+");
+ });
+ document.getElementById("ln").addEventListener('click', function() {
+ push("ln");
+ });
+ document.getElementById("num1").addEventListener('click', function() {
+ push("1");
+ });
+ document.getElementById("num2").addEventListener('click', function() {
+ push("2");
+ });
+ document.getElementById("num3").addEventListener('click', function() {
+ push("3");
+ });
+ document.getElementById("e").addEventListener('click', function() {
+ push("e");
+ });
+ document.getElementById("percent").addEventListener('click', function() {
+ push("%");
+ });
+ document.getElementById("num0").addEventListener('click', function() {
+ push("0");
+ });
+ document.getElementById("dot").addEventListener('click', function() {
+ push(".");
+ });
+ document.getElementById("backspace").addEventListener('click', function() {
+ var old_text = document.getElementById("text").innerHTML;
+ // 如果要删除的是函数(sin, ln等)或“Error”,则删除整体
+ if (/[a-z]$/.test(old_text)) {
+ document.getElementById("text").innerHTML = old_text.match(/.*?(?=(Error|sin|cos|tan|lg|ln)$)/)[0];
+ } else {
+ document.getElementById("text").innerHTML = old_text.substring(0, old_text.length - 1);
+ }
+ });
+ document.getElementById("clear").addEventListener('click', function() {
+ document.getElementById("text").innerHTML = "";
+ });
+ document.getElementById("equals").addEventListener('click', function() {
+ var text = document.getElementById("text").innerHTML;
+ document.getElementById("text").innerHTML = calc(text);
+ document.getElementById("text").classList.add("finish");
+ });
+}
+
+function push(str) {
+ var old_text = document.getElementById("text").innerHTML;
+ if (old_text == "Error" || /Infinity/.test(old_text)) {
+ old_text = "";
+ }
+ if (/^([0-9]|π|e|%|\.)$/.test(str) && document.getElementById("text").classList.contains("finish")) {
+ old_text = "";
+ }
+ document.getElementById("text").classList.remove("finish");
+ document.getElementById("text").innerHTML = old_text + str;
+}
diff --git a/js/main.js b/js/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..2323bd7e48e8fd72f240a12f06423b63117875cb
--- /dev/null
+++ b/js/main.js
@@ -0,0 +1,236 @@
+// 计算
+function calc(str) {
+ /*
+ 对象格式
+ (Root)[ // 要计算的表达式
+ (MathObject){ // 不含乘、除运算的式子
+ sign: 1 // 符号
+ expression: (SymbolArray)[
+ (Symbol){ // 一个数字或运算符
+ type: "number",
+ value: "123"
+ },
+ (Symbol){
+ type: "operation"
+ value: "sin"
+ },
+ (Symbol){...},
+ (Symbol){...},
+ ...
+ ]
+ },
+ (MathObject){...},
+ (MathObject){...},
+ ...
+ ]
+ */
+ try {
+ // 无内容,返回空字符串
+ if (str == "") {
+ return "";
+ }
+ // 检查表达式语法
+ // 百分号后不允许出现数字
+ if (/%([0-9]?\.[0-9]?|[0-9]+)/.test(str)) {
+ throw new Error("Unexpected number after %");
+ }
+ // 不允许出现连续的加号或减号
+ if (/[+-]{2}/.test(str)) {
+ throw new Error("Plus or minux can't appear together.");
+ }
+ // 一个数字中不允许出现两个小数点
+ if (/\.[0-9]*\./.test(str)) {
+ throw new Error("Unexpected number.");
+ }
+ // 末尾如果有加号或减号,则加一个0
+ if (/[+-]$/.test(str)) {
+ str += "0";
+ }
+ // 构造Root对象
+ var root = split(str);
+ for (var i = 0; i < root.length; i++) {
+ root[i].expression = buildSymbolArray(root[i].expression);
+ }
+ // console.log(root);
+ var result = 0; // 计算结果
+ // 逐个运算SymbolArray表达式的值
+ for (var i = 0; i < root.length; i++) {
+ // 如果符号是一个百分数,需要特别处理
+ if (root[i].expression.length == 1 && root[i].expression[0].type == "number" && /([0-9]+|[0-9]*\.[0-9]*)%/.test(root[i].expression[0].value)) {
+ // 如果该百分数是第一个式子,则正常运算
+ if (i != 0) {
+ // 此处特别处理,比如100+10%=110
+ result *= 1 + root[i].sign * parseNumber(root[i].expression[0].value);
+ } else {
+ result += root[i].sign * resolveSymbolArray(root[i].expression);
+ }
+ } else {
+ result += root[i].sign * resolveSymbolArray(root[i].expression);
+ }
+ }
+ // console.log(result);
+ if (isNaN(result)) {
+ throw new Error("Invalid calculation result.");
+ }
+ // 保留11位小数
+ return parseFloat(result.toFixed(11));
+ } catch (e) {
+ console.error(e);
+ return "Error";
+ }
+}
+
+// 拆分+、-
+function split(str) {
+ // 如果第一个字符不是正号或负号,则手动加一个正号
+ if (str[0] != '+' && str[0] != '-') {
+ str = '+' + str;
+ }
+ var array = new Array();
+ var index = 1;
+ while (index <= str.length) {
+ if (index == str.length || str[index] == '+' || str[index] == '-') {
+ array.push({
+ sign: str[0] == '+' ? 1 : -1,
+ expression: str.substring(1, index)
+ });
+ str = str.substring(index, str.length)
+ var index = 1;
+ continue;
+ }
+ index++;
+ }
+ return array;
+}
+
+// 构造SymbolArray
+function buildSymbolArray(str) {
+ var symbolArray = new Array();
+ var number_re = /^(([0-9]*\.[0-9]*|[0-9]+)%?|π|e)/; // 匹配数字的正则表达式
+ var operation_re = /^(sin|√|\^|cos|÷|×|tan|-|lg|+|ln)/; // 匹配运算符的正则表达式
+ while (str.length != 0) {
+ if (number_re.test(str)) {
+ var result = str.match(number_re)[0];
+ symbolArray.push({
+ type: "number",
+ value: result
+ });
+ str = str.substring(result.length);
+ } else if (operation_re.test(str)) {
+ var result = str.match(operation_re)[0];
+ symbolArray.push({
+ type: "operation",
+ value: result
+ });
+ str = str.substring(result.length);
+ } else {
+ // 错误
+ throw new Error("Building symbol array failed.");
+ }
+ }
+ return symbolArray;
+}
+
+// 计算SymbolArray的值
+function resolveSymbolArray(symbolArray) {
+ // 如数组为空,返回乘法元1
+ if (symbolArray.length == 0) {
+ return 1;
+ }
+ // 第一个符号是数字
+ if (symbolArray[0].type == "number") {
+ var value = parseNumber(symbolArray.shift().value);
+ // 没有第二个符号
+ if (symbolArray.length == 0) {
+ return value;
+ }
+ // 第二个符号也是数字,比如2π
+ if (symbolArray[0].type == "number") {
+ return value * resolveSymbolArray(symbolArray);
+ } else {
+ var operation = symbolArray[0].value;
+ // 一元运算符
+ if (operation == "sin" || operation == "sqrt" || operation == "cos" || operation == "tan" || operation == "lg" || operation == "ln" || operation == "√") {
+ return value * resolveSymbolArray(symbolArray);
+ }
+ // 二元运算符
+ else {
+ symbolArray.shift();
+ if (symbolArray.length == 0) {
+ // 二元运算符后面没有内容,报错
+ throw new Error("No number or operation after symbol " + operation);
+ }
+ var object = symbolArray[0]; // 二元运算符后面的第一个符号
+ if (object.type == "number") {
+ // 数字和数字运算
+ symbolArray.shift();
+ var number = parseNumber(object.value);
+ if (operation == "^") {
+ return Math.pow(value, number) * resolveSymbolArray(symbolArray);
+ } else if (operation == "×") {
+ return value * number * resolveSymbolArray(symbolArray);
+ } else if (operation == "÷") {
+ return value / number * resolveSymbolArray(symbolArray);
+ }
+ } else {
+ // 数字和函数运算,如3×sin6
+ if (operation == "^") {
+ return Math.pow(value, resolveSymbolArray(symbolArray));
+ } else if (operation == "×") {
+ return value * resolveSymbolArray(symbolArray);
+ } else if (operation == "÷") {
+ return value / resolveSymbolArray(symbolArray);
+ }
+ }
+ }
+ }
+ }
+ // 第一个符号是运算符
+ else {
+ var operation = symbolArray.shift().value;
+ // 该符号是一元运算符
+ if (operation == "sin" || operation == "sqrt" || operation == "cos" || operation == "tan" || operation == "lg" || operation == "ln" || operation == "√") {
+ // 运算符后面没有内容,报错
+ if (symbolArray.length == 0) {
+ throw new Error("No number or operation after symbol " + operation);
+ }
+ if (operation == "sin") {
+ return Math.sin(resolveSymbolArray(symbolArray));
+ } else if (operation == "sqrt") {
+ return Math.sqrt(resolveSymbolArray(symbolArray));
+ } else if (operation == "cos") {
+ return Math.cos(resolveSymbolArray(symbolArray));
+ } else if (operation == "tan") {
+ return Math.tan(resolveSymbolArray(symbolArray));
+ } else if (operation == "lg") {
+ return Math.log10(resolveSymbolArray(symbolArray));
+ } else if (operation == "ln") {
+ return Math.log(resolveSymbolArray(symbolArray));
+ } else if (operation == "√") {
+ return Math.sqrt(resolveSymbolArray(symbolArray));
+ }
+ }
+ // 该符号不是一元运算符,报错
+ else {
+ throw new Error("The first operation number is missing around " + operation);
+ }
+ }
+}
+
+// 转换数字
+function parseNumber(str) {
+ if (str == "e") {
+ return Math.E;
+ }
+ if (str == "π") {
+ return Math.PI;
+ }
+ var number = parseFloat(str);
+ if (/%$/.test(str)) {
+ number *= 0.01;
+ }
+ if (isNaN(number)) {
+ throw new Error("Cannot parse number " + str);
+ }
+ return number;
+}