动态创建重量输入框并计算总重:是否需用MutationObserver?
问题解答
1. 是否必须使用MutationObserver?
不需要。因为动态输入框是由我们自己的代码生成的,完全可以在创建每个重量输入框的同时直接绑定重量变化的监听事件,不需要借助MutationObserver去监听DOM变动后再绑定事件。这种方式更直接,避免了Observer带来的额外性能开销和逻辑复杂度。
2. 代码是否合理,有无更简便实现?
原代码的规模不算过度冗余,但确实有优化空间:重复的DOM创建逻辑可以封装复用,重量校验的事件监听可以直接整合到输入框创建步骤中,同时简化重量计算逻辑,让代码更紧凑。
优化后的完整代码
HTML
<div id="total-order-weight">20</div> <div id="over-weight-alert" style="display:none; color:red;">OVER WEIGHT</div> <form action="#" id="parcel-form" method="post"> <div class="multiparcel"> <input type="number" class="qty" min="0"> <div class="parcels"></div> </div> <button id="submit" class="btn btn-success mt-3" type="submit">Go</button> </form>
JavaScript
const overWeightAlert = document.querySelector('#over-weight-alert'); const totalOrderWeight = parseInt(document.querySelector('#total-order-weight').textContent); const parcelForm = document.querySelector('#parcel-form'); const qtyEl = document.querySelector('.qty'); const submitButton = document.querySelector('#submit'); // 通用表单元素创建函数,复用重复逻辑 function createFormField(labelText, name, type = 'number', defaultValue = '') { const label = document.createElement('label'); label.htmlFor = name; label.textContent = labelText; label.classList.add('form-label'); const input = document.createElement('input'); input.name = name; input.type = type; input.classList.add('form-control'); input.value = defaultValue; const container = document.createElement('div'); container.append(label, input); return container; } // 清空包裹输入组 function clearParcels(container) { container.innerHTML = ''; } // 添加指定数量的包裹输入组,同时绑定重量监听 function addParcels(container, count) { clearParcels(container); for (let i = 0; i < count; i++) { const group = document.createElement('div'); group.classList.add('input-group', 'my-2'); // 创建重量输入框并直接绑定校验事件 const weightField = createFormField('Poids', `weight${i}`, 'number'); const weightInput = weightField.querySelector('input'); weightInput.classList.add('me-4'); weightInput.addEventListener('input', checkWeightStatus); // 创建保险输入框 const insuranceField = createFormField('Assurance', `insurance${i}`, 'number', '0'); insuranceField.querySelector('input').classList.add('ms-4'); group.append(weightField, insuranceField); container.append(group); } } // 计算总重量并更新提示与按钮状态 function checkWeightStatus() { const weightInputs = parcelForm.querySelectorAll('input[name^="weight"]'); const totalWeight = Array.from(weightInputs).reduce((sum, input) => { return sum + (parseInt(input.value) || 0); }, 0); if (totalWeight > totalOrderWeight) { overWeightAlert.style.display = 'block'; submitButton.classList.add('d-none'); submitButton.classList.remove('d-block'); } else { overWeightAlert.style.display = 'none'; submitButton.classList.remove('d-none'); submitButton.classList.add('d-block'); } } // 监听包裹数量输入变化 qtyEl.addEventListener('input', (e) => { const parcelsContainer = e.target.closest('.multiparcel').querySelector('.parcels'); const count = parseInt(e.target.value) || 0; addParcels(parcelsContainer, count); });
优化点说明
- 封装
createFormField函数,减少重复的DOM创建代码 - 在创建重量输入框时直接绑定校验事件,彻底去掉MutationObserver
- 使用
reduce简化总重量计算逻辑,代码更简洁 - 统一使用
const/let声明变量,避免全局变量污染 - 逻辑更紧凑,减少不必要的DOM重复查询
内容的提问来源于stack exchange,提问作者Abpostman1
相关产品推荐
相关产品推荐

