首页 前端知识 基于Html, Css与Java Sctipt, Python的前后端计算器(附源码链接)

基于Html, Css与Java Sctipt, Python的前后端计算器(附源码链接)

2024-03-20 11:03:43 前端知识 前端哥 900 891 我要收藏

I.  文章概览

在这篇博文中,我将详细介绍前端和后端交互式Web计算器的实现,并展示最终产品。

我制作的这个计算器可以实现加、减、乘、除、清零、幂函数、三角函数、指数函数、反三角函数和ans运算。

Link to the finished project code: Assignment2 codes in github 

II. 作者与作品的基本信息

Course for This Assignment2301-MUSE社区-CSDN社区云
Assignment RequirementsSecond assignment-- Back-end separation calculator programming-CSDN社区
The Aim of This AssignmentImprove the function of calculator and realize front-end interaction
MU STU ID and FZU21126259_832101125

目录

I.  文章概览

II. 作者与作品的基本信息

III. PSP表格

IV. 成品界面展示

①网页调试图

② 基础运算

③三角函数计算

④ 反三角函数计算

 ④ 对数函数计算

⑤ 历史记录存储

 V. 项目设计思路

①前端设计思路:

②后端设计思路:

 VII. 代码解释

①前端代码解释

a. Java Script

b. HTML

c. Css

 ②Back-end Programming Implementation (Python)

VII. 项目未来规划

VIII. 设计参考文献


III. PSP表格

PSP Table
PSPEstimated time (minutes)Actual time (minutes)
Planning
• Estimate:4040
Development
• Analysis3030
• Design Spec2020
• Design Review1010
• Coding Standard:2020
• Design3030
• Coding300500
• Code Review100100
• Test2030
Reporting
• Test Report:55
• Size Measurement1010
• Postmortem & Process Improvement Plan1010
TOTAL TIME595805

IV. 成品界面展示

①网页调试图

② 基础运算

③三角函数计算

sin(x):

cos(x):

tan(x):

④ 反三角函数计算

 asin(x):

acos(x):

atan(x):

 ④ 对数函数计算

⑤ 历史记录存储


 V. 项目设计思路

①前端设计思路:

a. HTML 结构:创建一个 HTML 文件来定义网页的结构。添加输入字段、按钮和其他元素,使用户能够输入数学表达式并进行计算。

b. CSS 样式:使用 CSS 美化网页,使其看起来吸引人并易于使用。

c. JavaScript 交互:使用 JavaScript 编写前端逻辑,实现以下功能:

     监听按钮点击事件以捕获用户输入。

     动态显示用户输入的数学表达式在输入框中。

     处理用户点击等号按钮时的表达式求值。

     在网页上显示计算结果。

d. 用户体验(UX):确保用户界面友好且易于使用。添加错误处理,如除零错误、反三角函数超过阈值错误等,以提高用户体验。

②后端设计思路:

a. Python 后端:使用 Python 编写后端代码,使用 PyCharm 进行开发。后端的主要作用是处理来自前端的请求,执行计算操作,并将结果返回给前端。

b. API 设计:设计两个 API,分别用于存储和读取。

c. 数据库连接:使用 PyMySQL 连接数据库并执行必要的数据库操作,以存储计算历史或其他数据。

d. 结果返回:将存储的表达式及其对应的计算结果以 JSON 格式发送回前端。务必处理任何潜在的错误或异常,以提供友好的错误消息。

e. 部署:将 Python 后端部署到本地服务器,确保它能够响应前端的请求。


 VII. 代码解释

①前端代码解释

a. Java Script

// 这个函数用于将输入添加到显示框中
function display(input) {
  const str = document.getElementById("text");
  str.value += input;
}

// 这个异步函数执行计算,处理数学表达式
async function equals() {
  const str = document.getElementById("text");
  let input = str.value;
  let lastExpression = input;

  // 如果输入包含 'Ans',尝试获取答案并替换 'Ans' 为答案的值
  if (input.includes('Ans')) {
    try {
      const ansValue = await getAns();
      input = input.replace(/Ans/g, ansValue);
    } catch (error) {
      console.error('获取答案出错: ' + error);
    }
  }

  // 处理三角函数和反三角函数
  if (input.includes('asin') || input.includes('acos')) {
    const asinMatch = input.match(/asin\(([^)]+)\)/);
    const acosMatch = input.match(/acos\(([^)]+)\)/);

    if (asinMatch) {
      const x = parseFloat(asinMatch[1]);
      if (x < -1 || x > 1) {
        str.value = "Error: Invalid input for asin(x). x must be in the range [-1, 1].";
        return;
      }
    }

    if (acosMatch) {
      const x = parseFloat(acosMatch[1]);
      if (x < -1 || x > 1) {
        str.value = "Error: Invalid input for acos(x). x must be in the range [-1, 1].";
        return;
      }
    }
  }

  // 替换 '^' 运算符为 '**'
  if (input.includes('^')) {
    input = input.replace(/\^/g, '**');
  }

  // 替换三角函数和反三角函数为 Math 对象的方法
  if (input.includes('asin') || input.includes('acos') || input.includes('atan')) {
    input = input.replace(/(\b(asin|acos|atan))\(/g, 'Math.$2(');
  }

  // 替换 sin, cos, tan 为 Math.sin, Math.cos, Math.tan
  if (input.includes('sin') || input.includes('cos') || input.includes('tan')) {
    input = input.replace(/(\b(sin|cos|tan))\(/g, 'Math.$2(');
  }

  // 替换 'e' 为 Math.E,'π' 为 Math.PI
  if (input.includes('e')) {
    input = input.replace(/e/g, 'Math.E');
  }
  if (input.includes('π')) {
    input = input.replace(/π/g, 'Math.PI');
  }

  // 处理对数函数
  if (input.includes('log')) {
    input = input.replace(/log\(([^)]+)\)\(([^)]+)\)/g, 'Math.log($2) / Math.log($1)');
  }

  // 替换 'ln' 为 Math.log
  if (input.includes('ln')) {
    input = input.replace(/ln/g, 'Math.log');
  }

  // 替换 'Ans' 为上次计算的结果
  if (input.includes('Ans')) {
    let ansValue = getAns();
    input = input.replace(/Ans/g, ansValue);
  }

  // 处理除以 0 的情况
  if (input.includes('/0')) {
    str.value = "Error: Division by zero is not allowed";
    return;
  }

  try {
    // 使用 eval 函数计算表达式
    const result = eval(input);
    str.value = result;

    // 创建一个 XMLHttpRequest 对象并发送 POST 请求
    const xhr = new XMLHttpRequest();
    xhr.open('POST', 'http://localhost:5000/post', true);
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          const response = xhr.responseText;
          console.log(response);
        } else {
          console.error('请求失败,状态码:' + xhr.status);
        }
      }
    };
    const data = {
      expression: lastExpression,
      result: result
    };
    xhr.send(JSON.stringify(data));
  } catch (error) {
    str.value = "Error";
  }
}

// 删除最后一个字符
function back() {
  const str = document.getElementById("text");
  str.value = str.value.substring(0, str.value.length - 1);
}

// 重置显示框
function reset() {
  const str = document.getElementById("text");
  str.value = "";
}

// 将常数 Math.E 插入到显示框
function insertE() {
  const str = document.getElementById("text");
  str.value += Math.E;
}

// 在 getAns 函数中返回 Promise,用于获取答案
function getAns() {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:5000/get', true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          const Data = JSON.parse(xhr.responseText);
          const array = Data["data"];
          console.log(array);
          resolve(array[0][1]);
        } else {
          console.error('获取数据出错: ' + xhr.status);
          reject(xhr.status);
        }
      }
    };
    xhr.send();
  });
}

// 获取历史记录
function getHistory() {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', 'http://localhost:5000/get', true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        Data = JSON.parse(xhr.responseText);
        array = Data["data"];
        console.log(array);
        let string = "";
        for (let i = 0; i < array.length; i++) {
          string += array[i][0] + " = " + array[i][1];
          string += '\n';
        }
      } else {
        console.error('获取数据出错: ' + xhr.status);
      }
    }
  };
  xhr.send();
}

b. HTML

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>Simple Calculator in Web</title>
		<link href="css/PageSetting.css" rel="stylesheet" type="text/css" />
		<script type="text/javascript" src="js/CalculatorFunction.js"></script>
		<!-- <script type="text/javascript" src="js/history.js"></script>  -->
		<!-- <script type="text/javascript" src="js/localServer.js"></script> -->
	</head>
	
	<body>
		<div id="calculator">
			<div id="head"><h3>Simple Calculator in Web</h3></div>
			<div id="show" align="center"><input type="text" id="text" ></div>
			<div id="cuttom">
				<table align="center">
					<tr>
						<td><input type="button" value="e" onclick="display('e')"></td>
						<td><input type="button" value="π" onclick="display('π')"></td>
						
						<td><input type="button" value="(" onclick="display('(')"></td>
						<td><input type="button" value=")" onclick="display(')')"></td>
						
						<td><input type="button" value="^" onclick="display('^')"></td>
						<td><input type="button" value="history" onclick="getHistory()"></td>
					</tr>
					<tr>
						<td><input type="button" value="log" onclick="display('log(')"></td>
						<td><input type="button" value="ln" onclick="display('ln(')"></td>
						<td><input type="button" value="ans" onclick="display('Ans')"></td>
						<td><input type="button" value="asin" onclick="display('asin(')"></td>
						<td colspan="2"><input type="button" value="←" onclick="back()"></td>
					</tr>
					<tr>
						<td><input type="button" value="." onclick="display('.')"></td>
						<td><input type="button" value="0" onclick="display(0)"></td>
						<td><input type="button" value="acos" onclick="display('acos(')"></td>
						<td><input type="button" value="atan" onclick="display('atan(')"></td>
						<td colspan="2"><input type="button" value="c" onclick="reset()"></td>
					</tr>
					<tr>
						<td><input type="button" value="7" onclick="display(7)"></td>
						<td><input type="button" value="8" onclick="display(8)"></td>
						<td><input type="button" value="9" onclick="display(9)"></td>
						<td><input type="button" value="+" onclick="display('+')"></td>
						<td><input type="button" value="-" onclick="display('-')"></td>
						<td><input type="button" value="tan" onclick="display('tan(')"></td>
					</tr>
					<tr>
						<td><input type="button" value="4" onclick="display(4)"></td>
						<td><input type="button" value="5" onclick="display(5)"></td>
						<td><input type="button" value="6" onclick="display(6)"></td>
						<td><input type="button" value="*" onclick="display('*')"></td>
						<td><input type="button" value="/" onclick="display('/')"></td>
						<td><input type="button" value="sin" onclick="display('sin(')"></td>
					</tr>
					<tr>
						<td><input type="button" value="1" onclick="display(1)"></td>
						<td><input type="button" value="2" onclick="display(2)"></td>
						<td><input type="button" value="3" onclick="display(3)"></td>
						<td colspan="2"><input type="button" value="=" onclick="equals()"></td>
						<td><input type="button" value="cos" onclick="display('cos(')"></td>
					</tr>
				</table>
				
			</div>
		</div>
	</body>
</html>

c. Css

body {
    background: #f0f0f0;
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
}

#calculator {
    width: 600px;
    margin: 50px auto;
    border: 1px solid #ccc;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    background-color: #fff;
    border-radius: 10px; /* 添加圆角 */
    padding: 20px; /* 增加内边距 */
}

#head {
    background-color: #333;
    color: #fff;
    text-align: center;
    padding: 10px 0;
    border-radius: 10px; /* 添加圆角 */
}

#head h3 {
    margin: 0;
    font-size: 24px;
}

#show input {
    width: 100%;
    height: 60px;
    font-size: 30px;
    text-align: right;
    border: 2px solid black;
    padding: 10px;
    outline: none;
    box-sizing: border-box;
    border-radius: 10px; /* 添加圆角边框 */
}

#custom {
    padding: 20px;
}

table {
    width: 100%;
    table-layout: fixed;
    margin-top: 15px; /* 上方间隔 */
    margin-bottom: 15px; /* 下方间隔 */
}

table td {
    width: 25%;
    margin: 10px; /* 左右间隔 */
}

table input {
    width: 100%;
    height: 50px;
    font-size: 20px;
    text-align: center;
    border: none;
    outline: none;
    cursor: pointer;
    background: #f0f0f0;
    border-radius: 10px;
    box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2); /* 添加阴影效果 */
    transition: transform 0.2s, box-shadow 0.2s; /* 添加过渡效果 */
}



/* 鼠标悬停时应用立体效果和放大效果 */
table input:hover {
    background: #ccc;
    transform: scale(1.1); /* 放大效果 */
    box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2), 0 0 0 2px #000; /* 增加阴影深度和黑色边框 */
}

 ②Back-end Programming Implementation (Python)

/post API

  • 用于存储操作表达式和值。 客户端可以向该接口发送一个 POST 请求,传递一个包含表达式和计算结果的 JSON 数据。
  • 该接口将接收到的数据插入数据库,并确保保留最新的 10 条记录,删除多余的记录。
  • 返回一个 JSON 响应,包括消息 "ok" 表示操作成功,或错误消息和状态码 500 表示操作失败。
@app.route('/post', methods=['POST'])
def post_history():  # 存储运算表达式和值
    try:
        data = request.get_json()  # 获取POST请求的JSON数据
        expression = data.get('expression')
        result = data.get('result')

        time = datetime.datetime.now()

        # 插入新数据
        data = (time, expression, result)
        insert = "INSERT INTO history (time, expression, result) VALUES (%s, %s, %s)"
        cursor.execute(insert, data)

        # 获取当前记录数量
        cursor.execute("SELECT COUNT(*) FROM history")
        record_count = cursor.fetchone()[0]

        # 如果记录数量超过十条,删除最旧的记录
        if record_count > 10:
            delete_old_records = "DELETE FROM history ORDER BY time LIMIT %s"
            cursor.execute(delete_old_records, (record_count - 10,))

        conn.commit()

        response_message = "ok"
        return jsonify({"message": response_message})

    except Exception as e:
        error_message = str(e)
        return jsonify({"error": error_message}), 500
#用于存储运算表达式和值。
#客户端可以向此接口发送 POST 请求,传递一个 JSON 数据包括表达式和计算结果。
#该接口会将接收到的数据插入数据库中,并确保保留最新的 10 条记录,删除多余的记录。
#返回一个 JSON 响应,包括消息 "ok" 表示操作成功,或者包括错误消息和状态码 500 表示操作失败。

/get API

  • 用于获取历史操作表达式和结果。 客户端可以向该接口发送一个 GET 请求,以获取最新的 10 条历史记录。
  • 该接口在数据库中查询历史记录,并返回一个包含表达式和结果数据的 JSON 响应。
  • 如果查询失败,将返回一个错误消息和状态码 500。
@app.route('/get', methods=['GET'])
def get_calculation_data():  # 得到历史值
    try:
        cursor.execute("SELECT expression, result FROM history ORDER BY time DESC LIMIT 10")
        data = cursor.fetchall()
        return jsonify({"data": data})

    except Exception as e:
        error_message = str(e)
        return jsonify({"error": error_message}), 500
#用于获取历史运算表达式和结果。
#客户端可以向此接口发送 GET 请求,以获取最新的 10 条历史记录。
#该接口会查询数据库中的历史记录,并返回一个 JSON 响应,其中包括表达式和结果的数据。
#如果查询失败,将返回错误消息和状态码 500。

VII. 项目未来规划

通过设置新的交互栏和新的计算逻辑对用户进行分类,使特定用户可以直接使用与预期用途相关的计算键,如税收计算、游戏装备损坏计算等功能。


VIII. 设计参考文献

  • 【精选】2023 年 MySQL 8.0 安装配置 最简易(保姆级)_mysql8.0安装配置教程_mobeicanyue的博客-CSDN博客
  • web 技术中的前端和后端是如何交互的 - 知乎 (zhihu.com)
  • MySQL 管理 | 菜鸟教程 (runoob.com)
转载请注明出处或者链接地址:https://www.qianduange.cn//article/3968.html
标签
评论
发布的文章

JQuery操作DOM

2024-04-13 23:04:28

jQuery库

2024-04-13 23:04:28

【无标题】

2024-04-13 23:04:51

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!