在同一页面实现多个独立库存计数器:利用自定义元素解决状态隔离问题

在同一页面实现多个独立库存计数器:利用自定义元素解决状态隔离问题

本文介绍如何通过JavaScript自定义元素(Custom Elements)在同一网页上实现多个独立的动态库存计数器。针对传统方法中ID冲突和localStorage共享导致的问题,我们构建了一个可重用的组件,每个组件都能独立管理其库存数量,并支持通过localStorage进行持久化,从而解决多产品库存展示的难题。

传统库存计数器在多实例场景下的局限性

在网页中实现一个动态变化的库存计数器,通常会涉及到dom元素的更新和数据持久化。常见的做法是使用一个元素配合javascript来显示和更新数量,并通过localstorage来保存当前计数,以便页面刷新后能恢复状态。然而,当需要在同一页面上展示多个独立的库存计数器时,这种方法会遇到显著的问题:

ID冲突问题: 如果多个计数器都使用相同的ID(例如id=”qty”),document.getElementById()将只会获取到页面上的第一个匹配元素,导致其他计数器无法正常工作。localStorage共享问题: 如果所有计数器都使用相同的localStorage键来存储数量,它们将共享同一个库存值,一个计数器的变化会影响到所有其他计数器,无法实现独立管理。

简单地复制脚本并修改ID并不能解决localStorage共享的问题,因为每个脚本实例仍然会尝试读写同一个localStorage键,导致行为不一致。为了解决这些挑战,我们需要一种更组件化、更封装的解决方案。

引入自定义元素(Custom Elements)实现独立计数器

JavaScript的自定义元素(Custom Elements)提供了一种强大的方式来创建可重用的组件,它们拥有自己的生命周期、属性和方法,并且能够封装内部逻辑和状态。通过自定义元素,我们可以为每个库存计数器创建一个独立的实例,从而避免上述问题。

我们将创建一个名为的自定义元素。每个实例都可以独立地管理其库存数量,并可选择通过唯一的storage-key在localStorage中进行持久化。

自定义元素结构与核心逻辑

以下是定义自定义元素的完整代码:

customElements.define('stock-counter', class extends HTMLElement {  // quantity 属性的 getter 方法  get quantity() {    // 检查是否设置了 storageKey 且 localStorage 中存在有效值    if (this.storageKey !== null) {      const value = Number(localStorage.getItem(this.storageKey));      // 如果值是有效数字且不为0,则使用 localStorage 中的值      if (!Number.isNaN(value) && value !== 0) {        return value;      }    }    // 否则,从元素的 quantity 属性中获取初始值    const value = Number(this.getAttribute('quantity'));    // 如果 quantity 属性值无效,则返回 0    if (Number.isNaN(value)) {      return 0;    }    return value;  }  // quantity 属性的 setter 方法  set quantity(value) {    if (!isNaN(value)) {      // 如果设置了 storageKey,则将新值保存到 localStorage      if (this.storageKey !== null) {        localStorage.setItem(this.storageKey, value);      }      // 更新元素的 quantity 属性      this.setAttribute('quantity', value);    }  }  // storageKey 属性的 getter 方法  get storageKey() {    return this.getAttribute('storage-key');  }  // 当元素被添加到文档时调用  connectedCallback() {    this.count(); // 启动计数器  }  // 核心计数逻辑  count = () => {    const qty = this.quantity; // 获取当前数量    this.textContent = qty; // 更新元素显示的文本内容    if (qty === 0) {      return; // 如果数量为0,停止计数    }    let parts = Math.floor((Math.random() * 3) + 1); // 随机生成减少的数量 (1-3)    if (parts > qty) {      parts = qty; // 如果减少量大于当前数量,则减少量等于当前数量    }    this.quantity -= parts; // 更新数量(通过 setter 会自动更新 localStorage 和属性)    const msec = Math.floor(((Math.random() * 15) + 15) * 1000); // 随机生成延迟时间 (15-30秒)    setTimeout(this.count, msec); // 在指定延迟后再次调用 count 方法  };});

代码解析

customElements.define(‘stock-counter’, class extends HTMLElement { … });:

这是定义自定义元素的标准方式。’stock-counter’是元素的标签名,必须包含连字符。class extends HTMLElement表示我们的自定义元素继承自标准的HTMLElement接口,拥有所有HTML元素的特性。

quantity 属性(getter 和 setter):

get quantity(): 这是获取当前库存数量的逻辑。它首先检查元素是否设置了storage-key属性。如果设置了,它会尝试从localStorage中读取对应的值。如果localStorage中的值是一个有效的非零数字,则优先使用该值。这确保了页面刷新后能恢复上次的计数状态。如果localStorage中没有有效值,或者storage-key未设置,它会回退到从元素的quantity属性(HTML中的quantity=”…”)获取初始值。如果quantity属性值无效(例如非数字),则默认为0。set quantity(value): 这是设置库存数量的逻辑。当数量更新时,如果设置了storage-key,它会自动将新值保存到localStorage中。同时,它也会更新元素的quantity属性,确保DOM中的属性值与内部状态同步。

storageKey 属性(getter):

简单地返回元素storage-key属性的值。这个属性是可选的,用于指定localStorage的键名。

connectedCallback():

这是自定义元素的生命周期方法之一,当元素首次被添加到文档DOM时调用。在这里,我们调用this.count()来启动计数器逻辑。

count() 方法:

这是实现库存递减的核心逻辑。this.textContent = qty;:将当前库存数量显示在自定义元素内部。if (qty === 0) return;:当库存为0时,停止计数。let parts = Math.floor((Math.random() * 3) + 1);:随机生成每次递减的数量(1到3之间)。if (parts > qty) parts = qty;:确保递减的数量不会超过当前库存。this.quantity -= parts;:更新库存数量。由于quantity属性有setter,这会自动触发localStorage的更新。const msec = Math.floor(((Math.random() * 15) + 15) * 1000);:随机生成一个延迟时间(15到30秒之间)。setTimeout(this.count, msec);:在随机延迟后递归调用count方法,实现动态递减。

如何使用自定义元素

一旦自定义元素被定义,你就可以像使用任何标准HTML标签一样在页面中使用它。

405080

在上面的示例中:

每个元素都将独立运行。quantity属性定义了计数器的初始值。storage-key属性是可选的。如果设置了,该计数器的状态将通过这个唯一的键名在localStorage中持久化。这意味着刷新页面后,带有storage-key的计数器会从上次保存的值继续计数。没有storage-key的计数器将始终从quantity属性指定的初始值开始。元素内部的文本内容(例如40中的40)会在计数器启动后被更新为当前数量。

注意事项与总结

浏览器兼容性: 自定义元素是Web Components标准的一部分,现代浏览器(Chrome, Firefox, Edge, Safari)都已良好支持。对于旧版浏览器,可能需要引入Polyfill。storage-key的重要性: 如果你希望某个计数器的状态在页面刷新后依然保持,务必为其设置一个全局唯一的storage-key。不同的计数器使用相同的storage-key会导致它们共享状态,再次引入传统方法的缺陷。初始值与持久化: 当一个元素被加载时,它会优先尝试从localStorage中读取由storage-key指定的值。如果localStorage中没有有效值或storage-key未设置,它才会使用quantity属性作为初始值。封装性: 自定义元素将HTML结构、CSS样式(如果添加)和JavaScript行为封装在一起,提高了代码的可维护性和可重用性。

通过采用自定义元素,我们能够优雅地解决在同一页面上部署多个独立动态库存计数器的难题,为产品展示、活动倒计时等场景提供了强大而灵活的解决方案。这种组件化的方法不仅使代码更清晰,也大大提升了开发效率和用户体验。

以上就是在同一页面实现多个独立库存计数器:利用自定义元素解决状态隔离问题的详细内容,更多请关注创想鸟其它相关文章!

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

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
在React Native中集成Voximplant实现语音通话功能
上一篇 2025年12月20日 19:23:17
React Context与数组渲染:排查map函数常见错误指南
下一篇 2025年12月20日 19:23:34

相关推荐

  • Chrome浏览器怎么设置最小字体大小_网页最小显示字体设置教程

    Chrome浏览器怎么设置最小字体大小_网页最小显示字体设置教程Chrome浏览器怎么设置最小字体大小_网页最小显示字体设置教程Chrome浏览器怎么设置最小字体大小_网页最小显示字体设置教程Chrome浏览器怎么设置最小字体大小_网页最小显示字体设置教程

    首先调整Chrome最小字体设置至12像素以上,其次可通过页面缩放或开发者工具临时修改字体大小以提升可读性。 如果您发现Chrome浏览器中某些网页的字体过小导致阅读困难,这可能是因为浏览器或网页本身设置了较小的最小字体限制。以下是解决此问题的步骤: 本文运行环境:Dell XPS 13,Windo…

    2026年9月25日 • 用户投稿
    100
  • Java多态中成员变量是否具有动态绑定特性

    成员变量不具有动态绑定特性,其访问基于引用变量的声明类型而非实际对象类型。例如,当父类和子类存在同名成员变量时,通过父类引用访问该变量将获取父类中的值,即使实际对象是子类实例。这体现了静态绑定,即在编译期确定访问的变量。相比之下,实例方法支持动态绑定(后期绑定),在运行时根据对象的实际类型决定调用哪…

    2026年9月25日
    100
  • Java 中处理货币数据的正确方式

    Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式Java 中处理货币数据的正确方式

    在 Java 应用程序中,尤其是在处理财务数据时,选择正确的数据类型至关重要。货币数据通常以特定的格式呈现,例如包含货币符号(如美元符号 $)和千位分隔符(如逗号 ,)。直接将这些数据映射到 DTO 类时,我们需要仔细考虑数据类型的选择,以避免潜在的精度损失和计算错误。 货币数据类型选择考量 常见的…

    2026年9月25日 • 用户投稿
    000
  • 夸克怎么关闭自动打开淘宝_夸克禁止跳转第三方App设置

    夸克怎么关闭自动打开淘宝_夸克禁止跳转第三方App设置夸克怎么关闭自动打开淘宝_夸克禁止跳转第三方App设置夸克怎么关闭自动打开淘宝_夸克禁止跳转第三方App设置夸克怎么关闭自动打开淘宝_夸克禁止跳转第三方App设置

    关闭夸克浏览器“允许打开第三方应用”权限可解决跳转问题。依次进入设置→浏览器偏好→关闭该选项;同时在系统设置中将淘宝等App的链接打开方式设为“不打开”或“询问”;搜索时长按结果选择“在浏览器中打开”;使用无痕浏览模式避免唤端行为。 如果您在使用夸克浏览器时,点击链接后自动跳转到淘宝等第三方App,…

    2026年9月25日 • 用户投稿
    100
  • 如何在Debian上检测Nginx SSL状态

    在debian系统上检测nginx的ssl状态,可以通过以下几种方法进行: 使用Nginx命令行工具:打开终端,输入以下命令来检查Nginx的SSL配置是否正确: sudo nginx -t -c /etc/nginx/nginx.conf 这个命令会测试Nginx配置文件的语法是否正确,并且会显示…

    2026年9月25日
    000
  • Java 中处理货币数据的最佳实践

    Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践Java 中处理货币数据的最佳实践

    本文旨在探讨在 Java 中处理货币数据的最佳实践。面对 JSON 数据中包含的货币值(例如 “$234,205,860″),直接使用 String 存储是一种选择,但可能并非最优。本文将深入分析各种数据类型在处理货币时的优劣,并推荐使用 BigDecimal 进行精确计算,…

    2026年9月25日 • 用户投稿
    000
  • Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制

    Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制Java向上转型中可变参数方法调用的行为解析:重载与编译时绑定的深层机制

    本文深入探讨Java中向上转型、方法重载与可变参数(varargs)的交互机制。通过具体代码示例,详细解释了在向上转型场景下,为何编译器会基于引用变量的编译时类型来解析方法调用,即使子类存在看似更匹配的重载方法。核心在于方法重载是编译时决策,而可变参数在重载解析中具有较低的优先级。理解这些机制对于编…

    2026年9月25日 • 用户投稿
    000
  • VSCode如何通过SSH连接远程开发 VSCode远程SSH开发的配置与调试技巧

    安装“remote – ssh”扩展是实现vscode远程开发的基础;2. 配置ssh连接需在~/.ssh/config中设置host、hostname、user、port和identityfile等参数以实现快速连接;3. 连接成功后vscode会自动在远程安装vs code serv…

    2026年9月25日
    500
  • sublime怎么实时预览markdown文件 _sublime Markdown实时预览方法

    sublime怎么实时预览markdown文件 _sublime Markdown实时预览方法sublime怎么实时预览markdown文件 _sublime Markdown实时预览方法sublime怎么实时预览markdown文件 _sublime Markdown实时预览方法sublime怎么实时预览markdown文件 _sublime Markdown实时预览方法

    通过安装MarkdownPreview和LiveReload插件,可在Sublime Text中实现Markdown文件的准实时预览:先用Package Control安装插件,配置导出HTML到浏览器,再结合LiveReload实现保存即刷新,最后可设置Ctrl+Alt+M为快捷键,完成高效写作体…

    2026年9月25日 • 用户投稿
    400
  • Groovy编程:在HTTP请求头中传递授权令牌的实践指南

    Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南Groovy编程:在HTTP请求头中传递授权令牌的实践指南

    本教程详细介绍了如何在Groovy中通过HTTP请求头发送授权令牌,以实现对RESTful API的安全访问。针对用户在Groovy中模拟curl -H ‘Authorization: token …’命令时遇到的常见问题,本文提供了基于java.net.URL和…

    2026年9月25日 • 用户投稿
    900
  • 如何确保 Debian Node.js 日志的完整性

    如何确保 Debian Node.js 日志的完整性如何确保 Debian Node.js 日志的完整性如何确保 Debian Node.js 日志的完整性如何确保 Debian Node.js 日志的完整性

    维护 Debian Node.js 应用的日志完整性至关重要,这有助于监控服务器状态、排查问题和优化性能。以下步骤和建议能有效保障日志完整性: 日志库的选择 选择合适的日志库是第一步。以下列举了一些常用的选项,各有优劣: Winston: 广受欢迎,支持多种输出方式,配置灵活,易于设定日志存储位置。…

    2026年9月25日 • 用户投稿
    000
  • Spring Boot 应用:分离 REST API 和 Web 应用的最佳实践

    Spring Boot 应用:分离 REST API 和 Web 应用的最佳实践Spring Boot 应用:分离 REST API 和 Web 应用的最佳实践Spring Boot 应用:分离 REST API 和 Web 应用的最佳实践Spring Boot 应用:分离 REST API 和 Web 应用的最佳实践

    本文旨在探讨在 Spring Boot 项目中,如何有效地分离 REST API 和 Web 应用程序。针对小型项目,建议保持简单,将代码放在同一模块的不同包中。对于大型项目,则需要考虑可伸缩性、团队协作和性能需求,将前后端分离成两个独立的 Spring Boot 应用。文章将深入分析不同场景下的架…

    2026年9月25日 • 用户投稿
    300
  • uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置

    uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置uc浏览器如何阻止网页自动播放视频_UC浏览器禁止视频自动播放设置

    1、可通过UC浏览器设置关闭自动播放:进入设置→网站管理→媒体自动播放,选择关闭;2、启用省流加速模式减少视频自动加载;3、使用隐私模式浏览限制脚本执行,阻止视频自动播放。 如果您在使用UC浏览器浏览网页时,遇到视频自动播放影响阅读体验的情况,可以通过调整浏览器设置来禁止此行为。自动播放功能通常由浏…

    2026年9月25日 • 用户投稿
    600
  • 如何备份Claude聊天记录 Claude数据备份与恢复教程

    如何备份Claude聊天记录 Claude数据备份与恢复教程如何备份Claude聊天记录 Claude数据备份与恢复教程如何备份Claude聊天记录 Claude数据备份与恢复教程如何备份Claude聊天记录 Claude数据备份与恢复教程

    要备份claude聊天记录,可采取以下四种方法:一、打开对话点击菜单选择“导出对话”保存为文本文件;二、截图后用ocr工具提取文字并保存为文档;三、高级用户可用自动化工具或脚本自动抓取保存对话内容;四、误删后优先查看本地或云端备份,必要时联系客服。建议以预防为主定期备份确保数据安全。 ☞☞☞AI 智…

    2026年9月25日 • 用户投稿
    700
  • 通过索引访问 LinkedHashMap 的值

    通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值通过索引访问 LinkedHashMap 的值

    通过索引访问 LinkedHashMap 的值 本文将探讨如何比较两个 LinkedHashMap 中具有相同键的值,并提供一种有效的解决方案。LinkedHashMap 是一种可以保持插入顺序的 Map 实现,但它并不支持像 List 那样通过索引直接访问元素。因此,当我们需要比较两个 Linke…

    2026年9月25日 • 用户投稿
    1200
  • UC浏览器怎么录制网页视频_UC浏览器网页视频录制功能使用教程

    UC浏览器怎么录制网页视频_UC浏览器网页视频录制功能使用教程UC浏览器怎么录制网页视频_UC浏览器网页视频录制功能使用教程UC浏览器怎么录制网页视频_UC浏览器网页视频录制功能使用教程UC浏览器怎么录制网页视频_UC浏览器网页视频录制功能使用教程

    1、可通过UC浏览器录制功能保存网页视频:打开视频后使用系统录屏,选择媒体声音并开始录制,完成后自动保存至相册;2、部分视频支持嗅探下载:开启UC浏览器视频嗅探功能,识别视频资源后选择画质下载至Download目录;3、对于加密视频可启用开发者模式,通过检查元素捕获媒体请求链接,复制URL用第三方工…

    2026年9月25日 • 用户投稿
    100
  • 通过索引获取 LinkedHashMap 的值?解决方案与最佳实践

    通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践通过索引获取 LinkedHashMap 的值?解决方案与最佳实践

    本文旨在解决如何比较两个 LinkedHashMap 中具有相同键(chargeTypeName)的值的问题。由于 LinkedHashMap 本身不支持通过索引直接访问,文章将探讨如何利用流(Stream)和分组(Grouping)等技术,有效地找出两个 LinkedHashMap 中键相同的值对…

    2026年9月25日 • 用户投稿
    100
  • win7系统使用默认浏览器的设置方法

    win7系统使用默认浏览器的设置方法win7系统使用默认浏览器的设置方法win7系统使用默认浏览器的设置方法win7系统使用默认浏览器的设置方法

    我们都知道,系统默认启动的应用程序是预先设定好的,比如浏览器,默认情况下可能是某个特定的浏览器(如ie)。如果用户希望更换成其他浏览器,可以按照以下步骤进行设置。接下来,让我们一起看看具体的操作流程。 首先,点击屏幕左下角的“Windows”图标,然后从开始菜单中选择“控制面板”,如下图所示: 其次…

    2026年9月25日 • 用户投稿
    100
  • qq浏览器怎么用微信登录 QQ浏览器微信扫码快速登录指南

    qq浏览器怎么用微信登录 QQ浏览器微信扫码快速登录指南qq浏览器怎么用微信登录 QQ浏览器微信扫码快速登录指南qq浏览器怎么用微信登录 QQ浏览器微信扫码快速登录指南qq浏览器怎么用微信登录 QQ浏览器微信扫码快速登录指南

    首先通过电脑QQ浏览器点击微信图标获取二维码,用手机微信扫描并确认登录;或使用手机QQ浏览器扫描电脑端二维码,跳转微信验证后完成授权登录。 如果您在使用QQ浏览器时需要通过微信进行快捷登录,通常会通过扫描二维码的方式实现。以下是完成此操作的具体步骤: 本文运行环境:联想ThinkPad X1 Car…

    2026年9月25日 • 用户投稿
    200
  • 使用 Jackson 进行复杂类的自定义反序列化

    使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化使用 Jackson 进行复杂类的自定义反序列化

    本文介绍了如何使用 Jackson 库对包含复杂嵌套类的 JSON 字符串进行自定义反序列化。通过 ObjectMapper 的 readValue 方法可以实现简单场景下的自动反序列化。针对需要定制化处理的场景,可以结合 ObjectMapper 和自定义反序列化器来实现更灵活的反序列化逻辑,并提…

    2026年9月25日 • 用户投稿
    1000

发表回复

登录后才能评论
关注微信