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

news2024/12/23 10:22:33

<!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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2112402.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RISC-V架构下 DSA - AI算力的更多可能性:Banana Pi BPI-F3 进迭时空

AI已经从技术走向应用&#xff0c;改变了我们的生活和工作方式。近些年&#xff0c;AI算力芯片领域群雄逐鹿&#xff0c;通过对芯片、算力与AI三者发展迭代过程的理解&#xff0c;我们发现高能效比的算力、通用的软件栈以及高度优化的编译器&#xff0c;是我们的AI算力产品迈向…

稚晖君同款 clion嵌入式开发环境搭建

前言 前段时间看到稚晖君的单片机开发环境&#xff0c;感觉挺酷的&#xff0c;自己也想尝试下&#xff0c;这里记录下安装过程。 安装文件准备 stm32cubemx安装 stm32cubemx stm32cubemx下载地址 当前时间是2024年9月4日&#xff0c;下载的版本是6.12.0版本&#xff0c;下…

一、关系模型和关系代数,《数据库系统概念》,原书第7版

文章目录 [toc]一、引言1.1 什么是数据库1.2 数据完整性1.3 数据库的操作1.4 数据库的持久性1.5 数据库管理系统1.6 数据模型1.7 早期DBMS 二、关系模型2.1 什么是关系模型2.2 关系数据库的结构2.3 键2.4 约束2.5 数据操纵语言(DML)2.6 关系代数2.6.1 选择运算2.6.2 投影运算2.…

【南方科技大学】CS315 Computer Security 【Lab1 Packet Sniffing and Wireshark】

目录 IntroductionBackgroundTCP/IP Network StackApplication LayerTransport LayerInternet LayerLink LayerPacket Sniffer Getting WiresharkStarting WiresharkCapturing PacketsTest Run Questions for the Lab Introduction 实验的第一部分介绍数据包嗅探器 Wireshark。…

2024高教社杯全国大学生数学建模竞赛B题原创python代码

以下均为python代码。先给大家看看之前文章的部分思路&#xff1a; 接下来我们将按照题目总体分析-背景分析-各小问分析的形式来 1 总体分析 题目提供了一个电子产品生产的案例&#xff0c;要求参赛者建立数学模型解决企业在生产过程中的一系列决策问题。以下是对题目的总体…

Cortex-A7:简单中断处理(不可嵌套中断)机制

0 参考资料 ARM Cortex-A(armV7)编程手册V4.0.pdf ARM体系结构与编程第2版1 前言 Cortex-M系列内核MCU中断硬件原生支持嵌套中断&#xff0c;开发者不需要为了实现嵌套中断而进行额外的工作。但在Cortex-A7中&#xff0c;硬件原生是不支持嵌套中断的&#xff0c;这从Cortex-A…

隐私计算实训营:联邦学习在垂直场景的开发实践

纵向联邦学习 纵向联邦学习的参与方拥有相同样本空间、不同特征空间的数据&#xff0c;通过共有样本数据进行安全联合建模&#xff0c;在金融、广告等领域拥有广泛的应用场景。和横向联邦学习相比&#xff0c;纵向联邦学习的参与方之间需要协同完成数据求交集、模型联合训练和…

[Android] [SnapdragonCamera] 单摄(横屏)阶段总结

在研高通平台的单摄项目中遇到了很多适配问题&#xff0c;做一下初步的总结&#xff0c;为今后遇到相似的问题&#xff0c;提供参考方案。 1. 横屏设置相机预览显示不正常 1.1问题现象 1.2分析与解决 骁龙相机默认的预览方向是“portrait”。在横屏设备上显…

人车防撞系统安全生产方案

根据《市场监管总局关于2021~2023年全国特种设备安全状况的通告》数据显示&#xff1a;2023年&#xff1a;全国共发生特种设备事故和相关事故71起&#xff0c;其中死亡69人。包含叉车在内的场(厂)内专用机动车辆事故29起、死亡28人&#xff0c;占事故总数的40.85%、死亡人数的4…

DBeaver 常用操作

文章目录 快捷键SQL模板xml文件删除表数据执行脚本文件导入脚本表数据的标题栏中显示中文注释 (推荐)数据库导航显示表名 (推荐)执行多行sql语句ER图说明以及避坑 快捷键 执行sql语句&#xff1a;ctrlenter sql模板(可以自定义设置)&#xff1a;sf、swhere、scount 格式化&…

【吊打面试官系列-Redis面试题】Jedis 与 Redisson 对比有什么优缺点?

大家好&#xff0c;我是锋哥。今天分享关于 【Jedis 与 Redisson 对比有什么优缺点&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Jedis 与 Redisson 对比有什么优缺点&#xff1f; Jedis 是 Redis 的 Java 实现的客户端&#xff0c;其 API 提供了比较全面的 …

【CanMV K230】圆形检测

【CanMV K230】圆形检测 什么是圆形检测圆形检测应用领域1.工业自动化2.机器人视觉3.医学图像分析4.目标识别5.质量检测6.研究和开发 K230应用相关函数官方例程HDMI屏幕使用圆形检测 本篇内容&#xff1a; 什么是圆形检测圆形检测应用领域K230应用&#xff08;包含相应函数及例…

线性代数|机器学习-P34神经网络和学习函数

文章目录 1. 神经网络2. 损失函数3. 距离矩阵 1. 神经网络 构建一个神经网络步骤如下&#xff1a; 构建一个神经网络 构造一个学习函数 F ( x , v ) F(x,v) F(x,v),x代表权重 A k , b k A_k,b_k Ak​,bk​&#xff0c;v代表样本特征向量,ReLu激活函数 v 1 R e L u [ F ( A …

Leetcode 剑指 Offer II 094.分割回文串 II

题目难度: 困难 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定一个字符串 s&#xff0c;请将 s 分割成一些子串&#xff0c…

Clean Minimalist GUI Pack (简约风格UI界面)

Unity 最简洁易用的 GUI 资源包。如果你在寻找资源商店上 UI 极简主义革命的发起者,你已经找到了。 这一极干净简约的 GUI 资源包是一款适合移动设备使用的游戏 UI 资源包,其中包含许多图标和元素,可用于创建具有简洁风格的完整游戏 UI。 功能: • 包括 3 种皮肤:深色、浅…

C++编程语言:基础设施:表达式(Bjarne Stroustrup)

第10章 表达式(Expressions) 目录 10.1 引言 10.2 一个桌面计算器程序 10.2.1 解析器(Parser) 10.2.2 输入(Input) 10.2.3 底层输入(Low-Level Input) 10.2.4 错误处理(Error-Handling) 10.2.5 驱动器(Driver) 10.2.6 头文件(Headers) 10.2.7 命令行参数 …

全网最火的AI技术:Rag详解

“Rag”是机器学习中的术语&#xff0c;通常指的是“Ragged Tensors”&#xff08;不规则张量&#xff09;。Ragged Tensors 是一种特殊类型的张量&#xff0c;允许不同的维度中的子张量有不同的长度或形状。这在处理诸如文本、序列数据等不定长的数据时特别有用。例如&#xf…

WebShell流量特征检测_哥斯拉篇

90后用菜刀&#xff0c;95后用蚁剑&#xff0c;00后用冰蝎和哥斯拉&#xff0c;以phpshell连接为例&#xff0c;本文主要是对后三款经典的webshell管理工具进行流量分析和检测。 什么是一句话木马&#xff1f; 1、定义 顾名思义就是执行恶意指令的木马&#xff0c;通过技术手…

Pytorch环境搭建时的各种问题

1 问题 1.一直soving environment&#xff0c;跳不出去。网络解决方案有&#xff1a;配置清华源&#xff0c;更新conda等&#xff0c;没起作用。2.下载完后&#xff0c;有3个要done的东西&#xff0c;最后那个exe开头的&#xff08;可能吧&#xff09;&#xff0c;总是报错。网…

C++常见异常汇总(一)

文章目录 1、error: ‘__s_getMD5Sum’ is not a member2、Field has incomplete type2.1 处理方案1&#xff1a;使用前置声明2.1 处理方案2&#xff1a;使用静态变量 3、无法访问基类的public函数 1、error: ‘__s_getMD5Sum’ is not a member 错误现象&#xff1a; error: …