You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Django Web应用中所有卡片的增减按钮均可点击?

问题:Django循环生成的卡片仅第一个按钮生效

我用Django开发了一个Web应用,包含6个卡片,每个卡片都配有增减食品购买数量的按钮,但目前只有第一个卡片的按钮能正常工作。

原HTML代码

<div class="container">
    <div class="row">
        {% for roll in rolls %}
        <div class="col-4">
            <div class="card" style="width: 16rem;">
                <img src="{{ roll.immagine.url }}" class="card-img-top" alt="...">
                <div class="card-body">
                    <h5 class="card-title">{{ roll.nome }} Roll</h5>
                    <p class="card-text">€ {{ roll.prezzo }}</p>
                    <button id="incrementBtn" style="border-radius: 8px; background-color:orange;">+</button>
                    <span id="counter">0</span>
                    <button id="decrementBtn" style="border-radius: 8px; background-color: lightsalmon;">-</button>
                    <a href="{% url 'ordina' %}" class="btn btn-primary">Acquista</a>
                </div>
            </div>
        </div>
        {% endfor %}
    </div>
</div>

原JavaScript代码

document.addEventListener("DOMContentLoaded", function() {
    let idCounter = "counter1, counter2, counter3, counter4, counter5, counter6";
    let arrIdCounter = idCounter.split(", ");
    console.log(arrIdCounter);
    let valueCounter = document.getElementById('counter').innerHTML;

   const incrementBtn = document.getElementById('incrementBtn');
   const decrementBtn = document.getElementById('decrementBtn');

   incrementBtn.addEventListener('click', () => {
         console.log(valueCounter);
         valueCounter++;
         document.getElementById('counter').innerHTML = valueCounter;
         console.log(valueCounter);
   });

   decrementBtn.addEventListener('click', () => {
         if (valueCounter > 0) 
         {
             valueCounter--;
         }
         document.getElementById('counter').innerHTML = valueCounter;
  });
});

问题原因

核心问题是DOM中ID必须唯一,你通过Django循环生成的每个卡片里,按钮和计数器都使用了相同的id="incrementBtn"、id="decrementBtn"、id="counter",而document.getElementById()只会返回第一个匹配的元素,所以只有第一个卡片的按钮能触发事件。

解决方案

步骤1:修改HTML模板,替换ID为Class

把重复的ID改成Class,确保每个元素的标识不冲突:

<div class="container">
    <div class="row">
        {% for roll in rolls %}
        <div class="col-4">
            <div class="card" style="width: 16rem;">
                <img src="{{ roll.immagine.url }}" class="card-img-top" alt="...">
                <div class="card-body">
                    <h5 class="card-title">{{ roll.nome }} Roll</h5>
                    <p class="card-text">€ {{ roll.prezzo }}</p>
                    <button class="increment-btn" style="border-radius: 8px; background-color:orange;">+</button>
                    <span class="counter">0</span>
                    <button class="decrement-btn" style="border-radius: 8px; background-color: lightsalmon;">-</button>
                    <a href="{% url 'ordina' %}" class="btn btn-primary">Acquista</a>
                </div>
            </div>
        </div>
        {% endfor %}
    </div>
</div>

步骤2:修改JavaScript,使用事件委托处理点击

推荐用事件委托,只需绑定一次事件,就能处理所有卡片的按钮点击,还支持后续动态新增的卡片:

document.addEventListener("DOMContentLoaded", function() {
    // 监听全局点击事件,通过Class判断目标元素
    document.addEventListener('click', function(e) {
        // 处理增量按钮
        if (e.target.classList.contains('increment-btn')) {
            // 找到当前按钮所在的卡片容器
            const cardContainer = e.target.closest('.card-body');
            // 获取当前卡片的计数器
            const counter = cardContainer.querySelector('.counter');
            // 更新数值
            let currentValue = parseInt(counter.textContent);
            counter.textContent = ++currentValue;
        } 
        // 处理减量按钮
        else if (e.target.classList.contains('decrement-btn')) {
            const cardContainer = e.target.closest('.card-body');
            const counter = cardContainer.querySelector('.counter');
            let currentValue = parseInt(counter.textContent);
            if (currentValue > 0) {
                counter.textContent = --currentValue;
            }
        }
    });
});

如果偏好遍历绑定(适合静态渲染的元素),可以用以下代码:

document.addEventListener("DOMContentLoaded", function() {
    // 获取所有增量按钮并绑定事件
    document.querySelectorAll('.increment-btn').forEach(btn => {
        btn.addEventListener('click', function() {
            const counter = this.closest('.card-body').querySelector('.counter');
            let value = parseInt(counter.textContent);
            counter.textContent = ++value;
        });
    });

    // 获取所有减量按钮并绑定事件
    document.querySelectorAll('.decrement-btn').forEach(btn => {
        btn.addEventListener('click', function() {
            const counter = this.closest('.card-body').querySelector('.counter');
            let value = parseInt(counter.textContent);
            if (value > 0) {
                counter.textContent = --value;
            }
        });
    });
});

原理说明

  • 用Class代替重复ID,避免DOM元素标识冲突;
  • 通过closest('.card-body')定位按钮所在的卡片容器,确保每个按钮只操作自己卡片内的计数器;
  • 事件委托利用事件冒泡机制,在父元素上绑定一次事件,就能处理所有子元素的点击,性能更优且支持动态元素。

内容的提问来源于stack exchange,提问作者Gianmarco Polizia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 07:54:22