构建可配置的J*aScript加权点击计数器与共享总计功能


构建可配置的JavaScript加权点击计数器与共享总计功能

本文详细讲解如何使用j*ascript构建一个灵活的点击计数器系统。该系统支持两种计数模式:一种是每次点击增加1,另一种是每n次点击增加1。所有计数器的增量将实时累加到一个共享的总计显示区域,并通过扩展html数据属性实现高度可配置性,提供了一个可扩展且易于维护的解决方案。

在现代前端开发中,动态的用户交互是构建丰富体验的关键。点击计数器作为一种常见的交互元素,其需求可能不仅仅是简单的每次点击加一。有时,我们需要实现更复杂的逻辑,例如某个计数器每点击N次才对总数贡献1,而另一个计数器则每次点击贡献1。此外,所有这些独立的计数器可能需要将它们的“价值”累加到一个共享的总计显示区域。本教程将指导您如何通过扩展现有的J*aScript类和HTML数据属性,构建一个功能强大且高度可配置的加权点击计数器系统。

1. 需求分析与现有结构审视

我们的目标是实现以下功能:

  1. 两个独立的点击计数器,每个都有自己的显示和重置按钮。
  2. 一个名为“Verified Videos”的计数器,每次点击其按钮时,总计增加1。
  3. 一个名为“Document Count”的计数器,每当其点击次数达到9的倍数(9, 18, 27...)时,总计增加1。
  4. 页面底部有一个共享的“Total Units”显示区域,用于累加所有计数器的加权值。
  5. 每个计数器的重置操作应正确地从总计中减去其贡献值。

现有的J*aScript代码包含一个ClickCount类,它负责处理单个计数器的点击、显示和重置逻辑。HTML结构使用data-config-click属性来配置每个计数器。CSS则提供了基本的样式。

// 初始的 ClickCount 类(简化版,仅作参考)
class ClickCount {
  constructor(obj) {
    this.triggerNode = obj.triggerNode;
    this.targetNode = obj.targetNode;
    this.resetNode = obj.resetNode;
    this.count = 0;
    this.handleClick();
    this.handleCount();
  }

  handleClick() {
    this.triggerNode.addEventListener("click", () =>
      this.handleCount({ count: this.count++ })
    );
    this.resetNode.addEventListener("click", () => this.handleReset());
  }

  handleCount() {
    this.targetNode.innerHTML = this.count;
  }

  handleReset() {
    this.count = 0;
    this.handleCount();
  }
}

要实现加权总计功能,我们需要对这个类进行扩展,并修改HTML以传递更多配置信息。

2. 扩展HTML数据属性配置

为了让每个计数器能够定义其权重以及知道总计显示在何处,我们将扩展data-config-click属性。

  • weight: 定义权重,例如9表示每9次点击总计增加1,1表示每次点击总计增加1。
  • resultElement: 指定共享总计元素的CSS选择器,例如#total-units。

修改后的HTML结构如下:

<div class="block-wrapper">
  <div class="doctile">
    <div class="c-block" data-config-click='{"selectors":{"trigger":".button","target": ".result","reset":".button-reset", "weight": 9, "resultElement": "#total-units"}}'>
      <b class="result"></b>
      <button class="button button-primary" type="button">
        Document Count
      </button>
      <button class="button-reset">
        Reset
      </button>
    </div>
  </div>
  <div class="vidtile">
    <div class="c-block" data-config-click='{"selectors":{"trigger":".button","target": ".result","reset":".button-reset", "weight": 1, "resultElement": "#total-units"}}'>
      <b class="result"></b>
      <button class="button button-secondary" type="button">
        Verified Videos
      </button>
      <button class="button-reset">
        Reset
      </button>
    </div>
  </div>
</div>
<span class="totaltile">
  <p>Total Units =
    <span id="total-units">
      0
    </span>
  </p>
</span>

关键修改点:

Viggle AI Video Viggle AI Video

Powerful AI-powered animation tool and image-to-video AI generator.

Viggle AI Video 115 查看详情 Viggle AI Video
  • data-config-click中新增了"weight": 9(针对“Document Count”)和"weight": 1(针对“Verified Videos”)。
  • data-config-click中新增了"resultElement": "#total-units",指向共享总计的元素。
  • 页面底部的总计显示区域从document.write(this.count)改为一个带有id="total-units"的标签,并初始化为0。这是因为document.write(this.count)在J*aScript类外部无法正确访问this.count,且不适合动态更新。

3. 改造ClickCount类以支持加权总计

为了处理加权逻辑和更新共享总计,我们需要对ClickCount类进行以下增强:

  1. 构造函数扩展: 接收weight和resultNode参数。
  2. increaseTotal()方法: 计算当前计数器点击后对总计的增量。
  3. decreaseTotal()方法: 计算当前计数器重置后对总计的减量。
  4. 事件监听器集成: 在点击和重置事件中调用increaseTotal()和decreaseTotal()。
window.onload = () => { // 确保DOM完全加载后再执行脚本
  class ClickCount {
    constructor(obj) {
      this.triggerNode = obj.triggerNode;
      this.targetNode = obj.targetNode;
      this.resetNode = obj.resetNode;
      this.weight = obj.weight; // 新增:权重
      this.resultNode = obj.resultNode; // 新增:共享总计的DOM节点
      this.count = 0;
      this.handleClick();
      this.handleCount();
    }

    /**
     * 计算并增加总计值。
     * 该方法在每次点击事件发生时调用,
     * 它会根据当前计数器的权重,计算点击前后对总计的影响,并更新共享总计。
     */
    increaseTotal() {
      // 获取当前的总计值,如果是非数字则默认为0
      let currentTotal = isNaN(this.resultNode.innerHTML)
        ? 0
        : parseInt(this.resultNode.innerHTML);

      // 计算当前点击前的计数器对总计的贡献(基于this.count)
      const weightedCountBefore = parseInt(this.count / this.weight);
      // 从总计中减去旧的贡献
      currentTotal -= weightedCountBefore;

      // 计算点击一次后(this.count + 1)计数器对总计的新贡献
      const weightedCountAfter = parseInt((this.count + 1) / this.weight);
      // 将新的贡献加到总计中
      currentTotal += weightedCountAfter;

      // 更新共享总计的显示
      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(); // 更新当前计数显示
    }
  }

  // 初始化所有点击计数器
  const clickBlock = document.querySelectorAll("[data-config-click]");

  clickBlock.forEach((block) => {
    const config = JSON.parse(block.dataset.configClick);
    // 解构出新的配置参数
    const { trigger, target, reset, weight, resultElement } = config.selectors;
    const triggerNode = block.querySelector(trigger);
    const targetNode = block.querySelector(target);
    const resetNode = block.querySelector(reset);
    // 获取共享总计的DOM节点
    const resultNode = document.querySelector(resultElement);

    if (triggerNode && targetNode) {
      new ClickCount({
        triggerNode,
        targetNode,
        resetNode,
        resultNode, // 传递给构造函数
        weight, // 传递给构造函数
      });
    }
  });
};

代码解释:

  • window.onload = () => { ... }: 将所有J*aScript代码包裹在window.onload事件监听器中,确保在DOM完全加载和解析完毕后再执行脚本,避免因为元素未加载而导致的错误。
  • constructor(obj): 现在接收weight和resultNode,并将它们存储为实例属性。
  • increaseTotal():
    • 首先获取当前#total-units的文本内容并尝试解析为整数。isNaN检查用于处理初始或无效值,确保它从0开始。
    • weightedCountBefore = parseInt(this.count / this.weight):计算当前计数(点击前)对总计的贡献。
    • currentTotal -= weightedCountBefore:从总计中减去旧的贡献。
    • weightedCountAfter = parseInt((this.count + 1) / this.weight):计算点击后(this.count + 1)对总计的新贡献。
    • currentTotal += weightedCountAfter:将新的贡献加回总计。
    • 这种增量更新方式确保了即使权重很高(例如weight=9),总计也能正确地在9的倍数时增加1,而不是每次点击都重新计算整个计数器的总贡献。
  • decreaseTotal():
    • 在重置计数器之前,计算当前计数器在重置前对总计的贡献。
    • 从总计中减去这个贡献,然后才将this.count重置为0。这保证了总计的准确性。
  • handleClick(): 在递增this.count之前,先调用this.increaseTotal()来更新共享总计。
  • handleReset(): 在重置this.count为0之前,先调用this.decreaseTotal()来从共享总计中移除该计数器的贡献。
  • 初始化逻辑: clickBlock.forEach循环现在会从data-config-click中解析出weight和resultElement。然后,它使用document.querySelector(resultElement)获取到共享总计的DOM节点resultNode,并将这些新的参数一并传递给ClickCount的构造函数。

4. CSS样式(保持不变)

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;
}

5. 完整代码示例

为了方便您进行测试和部署,以下是完整的HTML、CSS和J*aScript代码。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Click counter</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div class="block-wrapper">
    <div class="doctile">
      <div class="c-block" data-config-click='{"selectors":{"trigger":".button","target": ".result","reset":".button-reset", "weight": 9, "resultElement": "#total-units"}}'>
        <b class="result"></b>
        <button class="button button-primary" type="button">
          Document Count
        </button>
        <button class="button-reset">
          Reset
        </button>
      </div>
    </div>
    <div class="vidtile">
      <div class="c-block" data-config-click='{"selectors":{"trigger":".button","target": ".result","reset":".button-reset", "weight": 1, "resultElement": "#total-units"}}'>
        <b class="result"></b>
        <button class="button button-secondary" type="button">
          Verified Videos
        </button>
        <button class="button-reset">
          Reset
        </button>
      </div>
    </div>
  </div>
  <span class="totaltile">
    <p>Total Units =
      <span id="total-units">
        0
      </span>
    </p>
  </span>
  <script src="./script.js"></script>
</body>
</html>

style.css

body {
  background: #000000;

以上就是构建可配置的J*aScript加权点击计数器与共享总计功能的详细内容,更多请关注其它相关文章!


# 潮品网站排名优化软件  # 它会  # 正确地  # 自己的  # 默认为  # 构建一个  # 都有  # 网站优化软件挣钱工作室  # 保定网站建设多少钱  # 选择器  # 六安律师网站推广  # 搜索seo思维导图  # app推广营销方案案例  # 地域词seo怎么做  # 长沙seo优化厂家电话  # 佛山网站开发建设  # 百度seo软件化  # css  # 加载  # 并将  # AI-powered  #   # mac  # ubuntu  # app  # go  # node  # json  # 前端  # js  # html  # java  # javascript 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 《崩坏:星穹铁道》3.6版本异相仲裁打法及配队推荐  猫眼电影app如何设置电影上映提醒_猫眼电影上映提醒设置教程  Python实战:高效处理实时数据流中的最小/最大值  《饿了么》拼好饭点外卖教程2025  CSS如何使用outline-offset与颜色组合突出元素边框  OPPO A3 WiFi频繁断开怎么办 OPPO A3网络优化技巧  mysql中外键约束如何使用_mysql FOREIGN KEY操作  拷贝漫画2025网页版入口 拷贝漫画官网免费看全集  j*a中赋值运算符是什么?  Python模块化编程:避免循环导入与共享函数的最佳实践  《美篇》取消会员自动续费方法  《宝可梦大集结》S4冠军之路开始时间介绍  如何定制PrimeNG Sidebar的背景颜色  电脑桌面图标怎么变大变小_Windows个性化设置第一课【新手入门】  创客贴登录页面入口 创客贴网页版最新网址链接  TikTok网页版入口快速访问 TikTok官网账号登录方法  《雷电模拟器》截图方法介绍  cad怎么隐藏指定的图层_cad隐藏或冻结图层方法  CDR如何复制交互式填充色  怎样让Windows 11的开始菜单恢复经典样式_Open-Shell工具使用指南【怀旧】  Mac如何开启画中画模式_Mac Safari浏览器视频画中画功能  向日葵客户端怎么进行语音通话_向日葵客户端语音通话功能使用方法  TikTok收藏夹无法删除视频如何解决 TikTok收藏管理优化方法  VS Code源代码管理(SCM)视图的进阶使用技巧  OPPO手机参数配置如何开启护眼模式_OPPO手机参数配置护眼模式开启指南  京东快递物流信息不更新怎么办_物流停滞原因与处理方法  《小黑盒》删除历史浏览方法  解决Pandas DataFrame高度碎片化警告:高效创建多列的策略  夸克浏览器资源嗅探怎么用 夸克浏览器网页资源下载技巧【教程】  NumPy 高性能技巧:基于多列条件查找最近邻行索引的向量化实现  快递物流路径揭秘  windows server2019显卡驱动怎么安装_winserver2019显卡驱动安装与远程桌面优化  《三角洲行动》战斗步枪与机枪类改装代码分享  Three.js中动态更换3D模型纹理的教程  《土豆雅思》修改密码方法  苹果手机缓存怎么清除_苹果手机缓存如何清除iphone各版本操作步骤  行者app怎样导出日志  荣耀Magic6 Pro拍照成像偏暗_荣耀Magic6 Pro夜景优化  WooCommerce购物车:强制显示所有交叉销售商品教程  OpenWeatherMap API:通过城市名称获取天气预报数据指南  《一起考教师》账号注销方法  《画加》约稿流程  PHP实现等比数列:构建数组元素基于前一个值递增的方法  苹果SE如何开启单手模式_苹果SE单手操作功能  泰拉瑞亚水晶无法放置问题  优化Asyncio嵌套函数调度:使用生产者-消费者模式实现并发流处理  手机雨课堂网页版入口免登录 雨课堂网页版可点击直接进入  C++中std::thread和std::async的区别_C++并发编程与线程与异步任务比较  Windows 11怎么删除恢复分区_Windows 11使用Diskpart命令强行删除分区  iPhone 13 mini如何清理Safari缓存_iPhone 13 mini浏览器缓存清理方法 

 2025-11-29

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.