使用JavaScript实现带权重和总计功能的双按钮点击计数器

使用JavaScript实现带权重和总计功能的双按钮点击计数器

本教程将指导您如何使用javascripthtml数据属性,构建一个包含两个独立点击计数器的页面,并实现一个全局总计功能。其中一个计数器每次点击使总计增加1,另一个计数器则按照设定的权重(例如每9次点击使总计增加1)来更新总计。我们将通过扩展现有的`clickcount`类和html配置来达到这一目标,确保代码模块化、易于维护。

教程背景与目标

在网页开发中,我们经常需要实现用户交互的计数功能。本教程将解决一个具体问题:在一个HTML页面上,存在两个独立的点击计数器,每个计数器都有自己的显示区域和重置按钮。在此基础上,我们需要添加一个全局的总计显示区域,该总计的更新规则如下:

当第一个按钮(例如“Verified Videos”)被点击时,全局总计直接增加1。当第二个按钮(例如“Document Count”)的点击次数达到特定倍数(例如9、18、27等)时,全局总计增加1(即每9次点击增加1)。

为了实现这一目标,我们将对现有的JavaScript ClickCount 类进行扩展,并优化HTML结构以传递必要的配置信息。

HTML结构优化:引入配置参数

为了使每个计数器能够灵活地配置其对全局总计的影响,我们将利用HTML的data-*属性来传递额外信息。具体来说,我们将扩展 data-config-click 属性,增加 weight 和 resultElement 两个字段。

weight: 用于指定该计数器对总计的权重。如果每次点击总计增加1,则 weight 为1。如果每N次点击总计增加1,则 weight 为N。resultElement: 用于指定全局总计显示元素的CSS选择器,以便JavaScript能够找到并更新它。

此外,我们需要一个专门的HTML元素来显示全局总计。

立即学习“Java免费学习笔记(深入)”;

更新后的 HTML (index.html):

    Click counter    

Total Units = 0

关键变化说明:

两个 c-block div 中的 data-config-click 属性都增加了 “weight” 和 “resultElement” 字段。”Document Count” 计数器设置 weight: 9,表示每9次点击总计增加1。”Verified Videos” 计数器设置 weight: 1,表示每次点击总计增加1。resultElement: “#total-units” 指向了页面底部的总计显示元素。页面底部添加了一个 span 元素,id=”total-units”,用于显示全局总计,并初始化为0。

CSS样式(保持不变)

CSS样式主要负责页面的布局和视觉呈现,对于本教程的功能实现没有直接影响,因此可以沿用原有的样式。

style.css (与原代码基本一致):

body {  background: #000000;  height: 100vh;  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;}.block-wrapper {  width: 100vw;  display: flex;  justify-content: center;  margin: auto;}.c-block {  margin: 50px;}button,b {  display: block;  text-align: center;}button {  border: none;  cursor: pointer;}button:focus {  outline: none;}.doctile {  background-color: #000000;  margin-top: 40px;  width: 375px;  height: 425px;  border-radius: 12px;  border: solid;  border-color: rgb(170, 170, 170, 0.5);  display: flex;  justify-content: center;  margin: 20px;}.vidtile {  background-color: #000000;  margin-top: 40px;  width: 375px;  height: 425px;  border-radius: 12px;  border: solid;  border-color: rgb(170, 170, 170, 0.5);  display: flex;  justify-content: center;  margin: 20px;}.button {  margin-top: 40px;  color: rgb(0, 190, 255);  padding: 4px 10px;  border-radius: 6px;  border: solid;  border-color: rgb(170, 170, 170, 0.5);  font-size: 32px;}.button:hover {  opacity: 0.9;}.button[disabled] {  opacity: 0.7;  cursor: not-allowed;}.button-primary {  background-color: rgb(85, 85, 85, .4);}.button-secondary {  background-color: rgb(85, 85, 85, .4);}.button-reset {  background-color: rgb(85, 85, 85, .4);  display: block;  color: rgb(0, 190, 255);  margin: 12px auto 0;  font-size: 16px;  padding: 4px 56px;  border-radius: 6px;  border: solid;  border-width: 2px;  border-color: rgb(170, 170, 170, 0.5);}.result {  color: rgb(0, 190, 255);  font-size: 100px;  margin-bottom: 8px;}.totaltile {  width: 500px;  height: 50px;  padding: 4px 10px;  border-radius: 6px;  border: solid;  border-color: rgb(170, 170, 170, 0.5);  font-size: 32px;  display: flex;  justify-content: center;  margin: auto;}p {  color: rgb(0, 190, 255);  font-size: 25px;  margin-top: 10px;}

JavaScript逻辑实现:扩展ClickCount类

核心的逻辑修改将在 script.js 文件中完成。我们将扩展 ClickCount 类,使其能够处理全局总计的更新,并根据配置的 weight 值计算贡献。

更新后的 JavaScript (script.js):

window.onload = () => {  class ClickCount {    constructor(obj) {      this.triggerNode = obj.triggerNode;      this.targetNode = obj.targetNode;      this.resetNode = obj.resetNode;      this.weight = obj.weight; // 新增:权重      this.resultNode = obj.resultNode; // 新增:全局总计显示节点      this.count = 0;      this.handleClick();      this.handleCount();    }    /**     * 更新全局总计:增加当前计数器的贡献     * 逻辑:计算当前点击前后的加权贡献差值,并更新总计。     * 例如,如果weight=9,count从8到9,则加权贡献从0增加到1。     * 如果count从17到18,则加权贡献从1增加到2。     */    increaseTotal() {      // 获取当前全局总计,如果非数字则默认为0      let currentTotal = isNaN(this.resultNode.innerHTML)        ? 0        : parseInt(this.resultNode.innerHTML);      // 计算当前点击前,该计数器的加权贡献      const previousWeightedCount = parseInt(this.count / this.weight);      // 从总计中减去旧的加权贡献      currentTotal -= previousWeightedCount;      // 计算当前点击后(count + 1),该计数器的加权贡献      const newWeightedCount = parseInt((this.count + 1) / this.weight);      // 将新的加权贡献加回到总计中      currentTotal += newWeightedCount;      // 更新全局总计显示      this.resultNode.innerHTML = currentTotal;    }    /**     * 更新全局总计:减少当前计数器的贡献(用于重置)     * 逻辑:计算当前计数器的加权贡献,并从总计中减去。     */    decreaseTotal() {      // 获取当前全局总计,如果非数字则默认为0      let currentTotal = isNaN(this.resultNode.innerHTML)        ? 0        : parseInt(this.resultNode.innerHTML);      // 计算当前点击数对应的加权贡献      const weightedCount = parseInt(this.count / this.weight);      // 从总计中减去该贡献      currentTotal -= weightedCount;      // 更新全局总计显示      this.resultNode.innerHTML = currentTotal;    }    /**     * 处理点击事件     */    handleClick() {      this.triggerNode.addEventListener("click", () => {        this.increaseTotal(); // 在计数器自身增加前,先更新全局总计        this.handleCount({          count: this.count++, // 增加计数器自身点击数        });      });      this.resetNode.addEventListener("click", () => this.handleReset());    }    /**     * 更新计数器自身的显示     */    handleCount() {      this.targetNode.innerHTML = this.count;    }    /**     * 处理重置事件     */    handleReset() {      this.decreaseTotal(); // 在计数器自身重置前,先从全局总计中移除贡献      this.count = 0; // 重置计数器自身点击数      this.handleCount();    }  }  // 遍历所有配置了点击计数器的HTML块  const clickBlock = document.querySelectorAll("[data-config-click]");  clickBlock.forEach((block) => {    const config = JSON.parse(block.dataset.configClick);    // 解构获取所有配置参数,包括新增的 weight 和 resultElement    const { trigger, target, reset, weight, resultElement } = config.selectors;    // 获取DOM节点    const triggerNode = block.querySelector(trigger);    const targetNode = block.querySelector(target);    const resetNode = block.querySelector(reset);    // 获取全局总计显示节点    const resultNode = document.querySelector(resultElement);    // 确保关键节点存在,然后创建 ClickCount 实例    if (triggerNode && targetNode) {      new ClickCount({        triggerNode,        targetNode,        resetNode,        resultNode, // 传递全局总计节点        weight, // 传递权重      });    }  });};

关键 JavaScript 变化说明:

window.onload 包装: 将所有初始化代码放入 window.onload 事件监听器中,确保DOM完全加载后再执行脚本,避免因元素未加载而导致的错误。ClickCount 构造函数扩展:新增 this.weight 和 this.resultNode 属性,用于存储当前计数器的权重和全局总计的DOM节点。increaseTotal() 方法:这是实现加权总计的核心。它首先获取当前的全局总计。然后,它计算当前点击前(this.count)该计数器对总计的贡献 (parseInt(this.count / this.weight)),并从 currentTotal 中减去。接着,计算点击后(this.count + 1)该计数器对总计的贡献 (parseInt((this.count + 1) / this.weight)),并加回到 currentTotal 中。这种“先减后加”的逻辑确保了即使连续多次调用 increaseTotal,只要 this.count 未改变,总计也不会重复增加。它准确地反映了在 this.count 增加1时,加权总计是否应该增加1。最后,更新 resultNode 的 innerHTML。decreaseTotal() 方法:用于处理计数器重置时,从全局总计中移除其贡献。它计算当前 this.count 对应的加权贡献,并直接从 currentTotal 中减去。handleClick() 方法修改:在 this.count++ 之前调用 this.increaseTotal(),确保在更新自身计数的同时,也更新全局总计。handleReset() 方法修改:在 this.count = 0 之前调用 this.decreaseTotal(),确保在重置自身计数的同时,也从全局总计中移除其贡献。初始化逻辑修改:在 clickBlock.forEach 循环中,从 config.selectors 中解构出 weight 和 resultElement。使用 document.querySelector(resultElement) 获取全局总计的DOM节点 resultNode。在创建 ClickCount 实例时,将 resultNode 和 weight 作为参数传递进去。

运行效果与注意事项

完成上述HTML、CSS和JavaScript的修改后,保存文件并在浏览器中打开 index.html。

点击“Verified Videos”按钮,其自身计数会增加,同时页面底部的“Total Units”也会增加1。点击“Document Count”按钮,其自身计数会增加。每当其计数达到9、18、27等时,“Total Units”会增加1。每个计数器的“Reset”按钮将重置该计数器,并同时从“Total Units”中减去该计数器之前贡献的加权值。

注意事项:

DOM加载顺序: 使用 window.onload 是一个良好的实践,确保在JavaScript尝试访问DOM元素时,这些元素已经存在于文档中。数据属性的解析: JSON.parse() 用于将 data-config-click 属性中的JSON字符串转换为JavaScript对象。请确保JSON格式正确,否则会导致解析错误。全局总计的唯一性: resultElement 应该指向一个唯一的元素(例如通过 id 选择器),以便所有计数器都能更新同一个全局总计。整数除法: parseInt(count / weight) 实现了向下取整的整数除法,这正是计算加权贡献所需的行为。健壮性: 在 increaseTotal 和 decreaseTotal 方法中,通过 isNaN(this.resultNode.innerHTML) ? 0 : parseInt(this.resultNode.innerHTML) 来获取 currentTotal,增加了代码的健壮性,防止因 resultNode 内容非数字而导致的问题。

总结

通过本教程,我们成功地将两个独立的点击计数器与一个具有复杂加权规则的全局总计功能结合起来。我们利用HTML数据属性实现了灵活的配置,并通过扩展JavaScript类使其具备了管理全局总计的能力。这种模块化和可配置的设计模式在构建复杂的交互式网页应用时非常有用。

以上就是使用JavaScript实现带权重和总计功能的双按钮点击计数器的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1599804.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
如何使用LocalStorage持久化动态HTML表格数据
上一篇 2025年12月23日 14:05:58
解决浏览器自动播放限制:理解与合规实现
下一篇 2025年12月23日 14:06:14

相关推荐

  • 修复Django电商项目中AJAX过滤产品列表图片不显示问题

    在Django电商项目中,当使用AJAX动态加载过滤后的产品列表时,常遇到图片无法正常显示的问题。这通常是由于前端模板中图片加载方式(如data-setbg属性结合JavaScript库)与AJAX动态内容更新机制不兼容所致。解决方案是直接在AJAX返回的HTML中使用标准的标签来渲染图片,确保浏览…

    2026年5月10日
    000
  • 开源免费PHP工具 PHP开发效率提升利器

    推荐开源免费PHP开发工具以提升效率:VS Code、Sublime Text轻量高效,PhpStorm专业强大;调试用Xdebug、Kint、Ray;依赖管理选Composer;代码质量工具包括PHPStan、Psalm、PHP_CodeSniffer;数据库管理可用%ignore_a_1%MyA…

    2026年5月10日
    000
  • Matplotlib 地图中多类型图例的创建与优化

    Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化Matplotlib 地图中多类型图例的创建与优化

    本教程旨在解决matplotlib地图可视化中,如何在一个图例中同时展示颜色块(如区域分类)和自定义标记(如特定兴趣点)的问题。文章详细介绍了当传统`patch`对象无法正确显示标记时,如何利用`matplotlib.lines.line2d`创建标记图例句柄,并将其与颜色块图例句柄合并,从而生成一…

    2026年5月10日 用户投稿
    300
  • Golang JSON序列化:控制敏感字段暴露的最佳实践

    本教程探讨golang中如何高效控制结构体字段在json序列化时的可见性。当需要将包含敏感信息的结构体数组转换为json响应时,通过利用`encoding/json`包提供的结构体标签,特别是`json:”-“`,可以轻松实现对特定字段的忽略,从而避免敏感数据泄露,确保api…

    2026年5月10日
    000
  • 怎么在PHP代码中实现图片上传功能_PHP图片上传功能实现与安全处理教程

    首先创建含enctype的HTML表单,再用PHP接收文件,检查目录、移动临时文件,验证类型与大小,生成唯一文件名,并调整php.ini限制以确保上传成功。 如果您尝试在PHP项目中添加图片上传功能,但服务器无法正确接收或保存文件,则可能是由于表单配置、文件处理逻辑或安全限制的问题。以下是实现该功能…

    2026年5月10日
    300
  • 比特币新手教程 比特币交易平台有哪些

    比特币是一种去中心化的数字货币,基于区块链技术实现点对点交易,具有匿名性、有限发行和不可篡改等特点;新手可通过交易所购买,P2P交易获得比特币,常用平台包括Binance、OKX和Huobi;交易流程包括注册账户、实名认证、绑定支付方式、充值法币并下单购买,可选择市价单或限价单;比特币存储方式有交易…

    2026年5月10日
    000
  • HTML如何隐藏滚动条或去除滚动条

    滚动条可以存在也可以不存在,本文主要介绍了html 隐藏滚动条和去除滚动条的方法的相关资料,大家一起来学习一下html隐藏滚动条或去除滚动条的方法吧。 1. html 标签加属性 XML/HTML Code复制内容到剪贴板 2.body中加入以下代码 立即学习“前端免费学习笔记(深入)”; html…

    用户投稿 2026年5月10日
    100
  • Golang gRPC流式请求异常处理

    在Golang的gRPC流式通信中,必须通过context.Context处理异常。应监听上下文取消或超时,及时释放资源,设置合理超时,避免连接长时间挂起,并在goroutine中通过context控制生命周期。 在使用 Golang 和 gRPC 实现流式通信时,异常处理是确保服务健壮性的关键部分…

    2026年5月10日
    000
  • Go语言mgo查询构建:深入理解bson.M与日期范围查询的正确实践

    本文旨在解决go语言mgo库中构建复杂查询时,特别是涉及嵌套`bson.m`和日期范围筛选的常见错误。我们将深入剖析`bson.m`的类型特性,解释为何直接索引`interface{}`会导致“invalid operation”错误,并提供一种推荐的、结构清晰的代码重构方案,以确保查询条件能够正确…

    2026年5月10日
    100
  • vscode上怎么运行html_vscode上运行html步骤【指南】

    首先保存文件为.html格式,再通过浏览器或Live Server插件打开预览;推荐安装Live Server实现本地服务器运行与实时刷新,提升开发体验。 在 VS Code 上运行 HTML 文件并不需要复杂的配置,只需几个简单步骤即可预览页面效果。VS Code 本身是一个代码编辑器,不直接运行…

    2026年5月10日
    100
  • css max-height属性怎么用

    max-height 属性设置元素的最大高度。 说明 该属性值会对元素的高度设置一个最高限制。因此,元素可以比指定值矮,但不能比其高。不允许指定负值。 注意:max-height 属性不包括外边距、边框和内边距。 立即学习“前端免费学习笔记(深入)”; 值描述none 默认。定义对元素被允许的最大高…

    2026年5月10日
    100
  • 修复点击时按钮抖动:CSS垂直对齐实践

    本文探讨了在Web开发中,交互式按钮(如播放/暂停按钮)在点击时发生意外垂直位移的问题。通过分析CSS样式变化对元素布局的影响,我们发现这是由于按钮不同状态下的边框样式和内边距改变,以及默认的垂直对齐行为共同作用所致。核心解决方案是利用CSS的vertical-align属性,将其设置为middle…

    2026年5月10日
    100
  • Golang goroutine与channel调试技巧

    使用go run -race检测数据竞争,结合runtime.NumGoroutine监控协程数量,通过pprof分析阻塞调用栈,利用select超时避免永久阻塞,有效排查goroutine泄漏、死锁和数据竞争问题。 Go语言的goroutine和channel是并发编程的核心,但它们也带来了调试上…

    2026年5月10日
    000
  • 页面中文本域的值怎么设置

    标签定义多行的文本输入控件。 文本区中可容纳无限数量的文本,其中的文本的默认字体是等宽字体(通常是 Courier)。 可以通过 cols 和 rows 属性来规定 textarea 的尺寸,不过更好的办法是使用 CSS 的 height 和 width 属性。 注释:在文本输入区内的文本行间,用 …

    2026年5月10日
    000
  • 使用 Jupyter Notebook 进行探索性数据分析

    Jupyter Notebook通过单元格实现代码与Markdown结合,支持数据导入(pandas)、清洗(fillna)、探索(matplotlib/seaborn可视化)、统计分析(describe/corr)和特征工程,便于记录与分享分析过程。 Jupyter Notebook 是进行探索性…

    2026年5月10日
    000
  • 如何在HTML中插入表单元素_HTML表单控件与输入类型使用指南

    HTML表单通过标签构建,包含action和method属性定义数据提交目标与方式,常用input类型如text、password、email等适配不同输入需求,配合label、required、placeholder提升可用性,结合textarea、select、button等控件实现完整交互,是…

    2026年5月10日
    100
  • 前端缓存策略与JavaScript存储管理

    根据数据特性选择合适的存储方式并制定清晰的读写与清理逻辑,能显著提升前端性能;合理运用Cookie、localStorage、sessionStorage、IndexedDB及Cache API,结合缓存策略与定期清理机制,可在保证用户体验的同时避免安全与性能隐患。 前端缓存和JavaScript存…

    2026年5月10日
    200
  • HTML5网页如何实现手势操作 HTML5网页移动端交互的处理技巧

    首先利用原生touch事件实现滑动判断,再通过preventDefault解决滚动冲突,接着引入Hammer.js处理复杂手势,最后通过优化点击区域、避免事件冲突和增加视觉反馈提升体验。 在移动端浏览器中,HTML5网页可以通过触摸事件实现手势操作,提升用户体验。虽然原生JavaScript提供了基…

    2026年5月10日
    000
  • 创建指定大小并填充特定数据的Golang文件教程

    本文将介绍如何使用Golang创建一个指定大小的文件,并用特定数据填充它。我们将使用 `os` 包提供的函数来创建和截断文件,从而实现快速生成大文件的目的。示例代码展示了如何创建一个10MB的文件,并将其填充为全零数据。掌握这些方法,可以方便地在例如日志系统或磁盘队列等场景中,预先创建测试文件或初始…

    2026年5月10日
    000
  • 深入理解 Express.js 中 next() 参数的作用与中间件机制

    本文深入探讨 express.js 中间件函数中的 `next()` 参数。它负责将控制权传递给请求-响应周期中的下一个中间件或路由处理程序。文章将详细解释 `next()` 的工作原理、中间件的注册与执行顺序,以及不正确使用 `next()` 可能导致请求挂起的风险,并通过代码示例和实际应用场景,…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信