html记账本改写:数据重新布局,更好用了,没有localStorage保存版本

本文主要是介绍html记账本改写:数据重新布局,更好用了,没有localStorage保存版本,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>htm记账本</title><style>table {user-select: none;/* width: 100%; */border-collapse: collapse;}table,th,td {border: 1px solid black;}th,td {padding: 8px;text-align: center;}</style>
</head>
<body><table id="ledgerTable"><thead><tr><th style="width: 50px;"><input type="month" id="monthPicker"></th><th colspan="3">日常开销</th></tr></thead><tbody><tr><td>日期</td><td>项目</td><td>支出</td><td>收入</td></tr></tbody><tfoot><tr><td><strong>总和</strong></td><td id="totalAmount">0</td><td id="totalExpense">0</td><td id="totalIncome">0</td></tr></tfoot></table><script>document.getElementById('monthPicker').addEventListener('change', function () {let selectedDate = new Date(this.value);let year = selectedDate.getFullYear();let month = selectedDate.getMonth();let daysInMonth = new Date(year, month + 1, 0).getDate();let tbody = document.querySelector('#ledgerTable tbody');// 清空现有内容并添加标题行tbody.innerHTML = `<tr><td>日期</td><td>项目</td><td>支出</td><td>收入</td></tr> `;// 为每一天添加行for (let day = 1; day <= daysInMonth; day++) {let newRow = document.createElement('tr');newRow.innerHTML = `<td>${day}</td><td><button class="add-item">+</button></td><td>0</td><td>0</td>`;newRow.querySelector('.add-item').addEventListener('click', addItemHandler);tbody.appendChild(newRow);}// 初始化总和updateTotals();});// 添加项目的事件处理函数function addItemHandler() {const newItem = createItemElement({ name: '', expense: '', income: '' });this.parentNode.insertBefore(newItem, this);updateDailyTotals(this.closest('tr'));updateTotals(); // 更新总和}// 创建项目元素的函数function createItemElement(item) {const newItem = document.createElement('div');newItem.innerHTML = `<input type="text" placeholder="项目" value="${item.name}"><select class="type-select"><option value="expense">支出</option><option value="income">收入</option></select><input type="number" placeholder="金额" style="width: 70px;" value="${item.expense || item.income || ''}"><button class="remove-item">-</button>`;// 获取金额输入框和类型选择框const amountInput = newItem.querySelector('input[type="number"]');const typeSelect = newItem.querySelector('.type-select');// 添加事件监听器addEventListeners(amountInput, typeSelect, newItem);// 给“-”按钮添加事件监听newItem.querySelector('.remove-item').addEventListener('click', function () {const row = this.closest('tr');// 弹出确认对话框const confirmDelete = confirm("确定要删除此项目吗?");if (confirmDelete) {this.parentNode.remove();updateDailyTotals(row);updateTotals(); // 更新总和saveData(); // 保存数据}});return newItem;}// 添加事件监听器的函数function addEventListeners(amountInput, typeSelect, newItem) {// 监听金额输入框的变化amountInput.addEventListener('input', function () {if (typeSelect.value === 'expense' && this.value > 0) {this.value = -this.value; // 如果选择“支出”且金额为正数,自动转换为负数}updateDailyTotals(newItem.closest('tr')); // 更新每日总和updateTotals(); // 更新总和});// 监听类型选择框的变化typeSelect.addEventListener('change', function () {if (this.value === 'expense') {// 如果选择“支出”,确保金额为负数if (amountInput.value > 0) {amountInput.value = -amountInput.value;}amountInput.min = '-999999';amountInput.max = '0';} else if (this.value === 'income') {// 如果选择“收入”,确保金额为正数if (amountInput.value < 0) {amountInput.value = -amountInput.value;}amountInput.min = '0';amountInput.max = '999999';}updateDailyTotals(newItem.closest('tr')); // 更新每日总和updateTotals(); // 更新总和});}// 更新每日总和的函数function updateDailyTotals(row) {const items = row.querySelectorAll('div');let expenseTotal = 0;let incomeTotal = 0;items.forEach(item => {const amountInput = item.querySelector('input[type="number"]');const amount = parseFloat(amountInput.value) || 0;if (amount < 0) {expenseTotal += amount;} else {incomeTotal += amount;}});row.querySelectorAll('td')[2].textContent = expenseTotal;row.querySelectorAll('td')[3].textContent = incomeTotal;}// 更新总和的函数function updateTotals() {const rows = document.querySelectorAll('#ledgerTable tbody tr');let totalExpense = 0;let totalIncome = 0;rows.forEach(row => {const expenseCell = row.querySelectorAll('td')[2];const incomeCell = row.querySelectorAll('td')[3];totalExpense += parseFloat(expenseCell.textContent) || 0;totalIncome += parseFloat(incomeCell.textContent) || 0;});document.getElementById('totalExpense').textContent = totalExpense;document.getElementById('totalIncome').textContent = totalIncome;document.getElementById('totalAmount').textContent = totalIncome + totalExpense;}</script>
</body>
</html>

这篇关于html记账本改写:数据重新布局,更好用了,没有localStorage保存版本的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147338

相关文章

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

MyBatis-plus处理存储json数据过程

《MyBatis-plus处理存储json数据过程》文章介绍MyBatis-Plus3.4.21处理对象与集合的差异:对象可用内置Handler配合autoResultMap,集合需自定义处理器继承F... 目录1、如果是对象2、如果需要转换的是List集合总结对象和集合分两种情况处理,目前我用的MP的版本

GSON框架下将百度天气JSON数据转JavaBean

《GSON框架下将百度天气JSON数据转JavaBean》这篇文章主要为大家详细介绍了如何在GSON框架下实现将百度天气JSON数据转JavaBean,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言一、百度天气jsON1、请求参数2、返回参数3、属性映射二、GSON属性映射实战1、类对象映

Ubuntu如何升级Python版本

《Ubuntu如何升级Python版本》Ubuntu22.04Docker中,安装Python3.11后,使用update-alternatives设置为默认版本,最后用python3-V验证... 目China编程录问题描述前提环境解决方法总结问题描述Ubuntu22.04系统自带python3.10,想升级

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十