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

JS中出现新子元素包含父元素的DOM异常问题求助

问题解决:贷款模拟页面的DOM错误与多笔贷款显示问题

错误原因分析

1. DOM异常错误

在classContenedor函数中执行了contenedor.append(contenedor),试图将容器元素添加到自身内部,违反DOM树层级规则,直接触发Uncaught DOMException错误。这行代码无实际作用,需直接删除。

2. 多笔贷款无法显示的问题

  • 重复绑定提交事件:每次循环都给同一个formPrestamo添加submit监听,导致提交时触发多次回调,数据逻辑混乱。
  • 结果内容被覆盖:使用contenedor.innerHTML = ...会清空原有内容,新贷款结果会替换旧记录,无法保留多笔数据。
  • 表单状态未重置:提交第一笔贷款后,未重置表单也未跟踪当前填写进度,导致第二笔数据覆盖第一笔的Prestamo实例。

修改后的代码

HTML代码(修正闭合标签+添加输入限制)

<div class="container principal pt-2 mb-3">
  <div class='row col-sm-12 mb-1'>
    <form id="formulario">          
      <div class="row col-sm-12 mb-1 d-flex justify-content-evenly">
        <label class="form-label col-12 col-lg-6 titulos" for='cantidadPrestamos'>¿Cuantos prestamos queres solicitar?</label>            
        <input class="col-12 col-lg-4 main m-2" id='cantidadPrestamos' name='full-name' type='number' min="1" max="2"/>
        <input class="col-12 col-lg-auto main m-2" type="submit" value="Enviar"> 
      </div>
    </form>
  </div>
</div>

<div id="display" class="container principal mb-2 d-none">
  <div class='row col-sm-12 mb-1'>
    <form id="formPrestamo">
      <div class="titulos mb-3 p-1 pt-3"> Necesitamos estos datos para cotizar tu prestamo:
      </div>
      <div class="row col-sm-12 mb-1">
        <label class="form-label col-12 col-lg-4" for='capital'>Capital (Minimo $10.000)</label>
        <input class="col-12 col-lg-8 main mb-2" id='capital' name='full-name' type='number' min="10000"/>
      </div>
      <div class='row col-sm-12 mb-1'>
        <label class="form-label col-12 col-lg-4" for='cuotas'>Cuotas (Maximo 60)</label>
        <input class="col-12 col-lg-8 main mb-2" id='cuotas' name='cuotas' type='number' max="60" min="1"/>
      </div>
      <div class='row col-sm-12 mb-1'>
        <label class="form-label col-12 col-lg-4" for='interes'>Interes</label>
        <input class="col-12 col-lg-8 mb-2 main" id='interes' name='interes' type="number" min="0"></input>
      </div>
      <div class='row mb-3 d-flex justify-content-center'>
        <input class="col-12 col-lg-6 main m-2" type="submit" value="Enviar">
      </div>  
    </form>
  </div>
</div>
<div id="contenedor"></div>

JavaScript代码

let cantidadPrestamos = 0;
let prestamos = [];
let currentLoanIndex = 0;

const formulario = document.getElementById("formulario");
const formPrestamo = document.getElementById("formPrestamo");
const contenedor = document.getElementById("contenedor");
const display = document.getElementById("display");

// 全局绑定表单事件(仅绑定一次)
formulario.addEventListener("submit", validateForm);
formPrestamo.addEventListener("submit", validateFormPrestamo);

function validateForm(event) {
    event.preventDefault();
    cantidadPrestamos = parseInt(event.target[0].value);
    // 重置申请状态
    prestamos = [];
    currentLoanIndex = 0;
    contenedor.innerHTML = "";
    // 显示贷款表单并重置
    display.classList.remove("d-none");
    formPrestamo.reset();
}

function Prestamo(capital, cantidadCuotas, interes, cuotaMes, devolucionTotal) {
    this.capital = capital;
    this.cantidadCuotas = cantidadCuotas;
    this.interes = interes;
    this.cuotaMes = cuotaMes;
    this.devolucionTotal = devolucionTotal;
}

function validateFormPrestamo(event) {
    event.preventDefault();
    const formData = event.target;
    const capital = parseInt(formData[0].value);
    const cuotas = parseInt(formData[1].value);
    const interes = parseFloat(formData[2].value) / 100;

    // 输入验证
    if (capital < 10000) {
        showError("El monto solicitado es insuficiente. El minimo es $10.000");
        return;
    }
    if (cuotas > 60) {
        showError("Excediste la cantidad de cuotas habilitadas");
        return;
    }

    // 计算贷款数据
    const tasa = (interes) => (1 + interes) ** (1/12) - 1;
    const cuotaMensual = (capital, tasa, cuotas) => (tasa * capital) / (1 - (1 + tasa) ** -cuotas);
    
    const monthlyRate = tasa(interes);
    const monthlyPayment = cuotaMensual(capital, monthlyRate, cuotas);
    const totalRepayment = monthlyPayment * cuotas;

    // 保存贷款实例
    const prestamo = new Prestamo(capital, cuotas, interes, monthlyPayment, totalRepayment);
    prestamos.push(prestamo);

    // 更新显示所有贷款
    renderLoans();

    // 控制表单显示逻辑
    currentLoanIndex++;
    if (currentLoanIndex >= cantidadPrestamos) {
        display.classList.add("d-none");
    } else {
        formPrestamo.reset();
    }
}

function renderLoans() {
    contenedor.className = "container principal subtitulos";
    contenedor.innerHTML = "";
    
    // 渲染每一笔贷款
    prestamos.forEach((prestamo, index) => {
        const loanElement = document.createElement("div");
        loanElement.className = "loan-item mb-4 p-3 border";
        loanElement.innerHTML = `
            <h3>Prestamo ${index + 1}: $${prestamo.capital}</h3>
            <p>Interes: ${prestamo.interes * 100}%</p>
            <p>Cuotas: ${prestamo.cantidadCuotas}</p>
            <p>Cuota mensual: $${prestamo.cuotaMes.toFixed(2)}</p>
            <p>Total a devolver: $${prestamo.devolucionTotal.toFixed(2)}</p>
        `;
        contenedor.appendChild(loanElement);
    });
}

function showError(message) {
    contenedor.className = "container principal subtitulos";
    contenedor.innerHTML = `<div class="alert alert-danger">${message}</div>`;
}

关键修改点

  1. 移除错误的DOM操作:删除contenedor.append(contenedor),将样式设置整合到渲染函数中。
  2. 单次事件绑定:将formPrestamo的提交事件移到全局绑定,避免重复绑定导致的逻辑冲突。
  3. 跟踪申请进度:用currentLoanIndex记录已完成的贷款数量,判断是否需要继续显示表单。
  4. 保留多笔记录:通过创建独立DOM元素并追加到容器,或清空后重新渲染所有贷款,避免内容覆盖。
  5. 状态重置:每次发起新申请时,重置贷款数组、索引和容器内容,清除旧数据干扰。
  6. 输入优化:HTML添加min/max限制输入范围,JS中补充验证并通过独立函数显示错误信息。

内容的提问来源于stack exchange,提问作者Nicolás Toranzo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:18:16