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

表单验证本地DOM操作遇Uncaught TypeError错误,求修复方案

表单验证报错:Uncaught TypeError: Cannot read properties of undefined (reading 'remove')

我需要实现以下表单验证功能:点击表单提交按钮时,若输入框为空或不符合邮箱格式,对应输入框旁需显示错误小图标,全程采用HTML、CSS、JS进行本地DOM操作。但目前运行时持续报错:Uncaught TypeError: Cannot read properties of undefined (reading 'remove'),相关代码如下:

错误代码

JavaScript

"use strict"

const form = document.querySelector(".form");
const inputs = document.getElementsByTagName("input");
const errorImg = document.querySelectorAll(".error-img");
const submitBtn = document.getElementById("submit-btn");


submitBtn.addEventListener("click", (e) => {
    e.preventDefault();

    if(!inputs.value){
        errorImg.classList.remove("hidden");
    } else {
        errorImg.classList.add("hidden");
    }
});

CSS

@import url(https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap);

body{
    margin: 0;
    background-image: url(images/bg-intro-desktop.png);
    background-color: rgba(255, 0, 0, .5);
    font-family: 'Poppins', sans-serif;
}

.container{
    margin: 6rem auto;
    height: auto;
    width: 70%;
    
    display: grid;
    grid-template-areas: 
    "left right"
    "left right";
    grid-auto-columns: minmax(0, 32rem);
}

.left-container{
    grid-area: left;
}

.left-heading{
    color: white;
    font-size: 2.7rem;
    line-height: 3rem;
    font-weight: 700;

    position: relative;
    top: 30%;
}

.left-content{
    color: white;
    font-size: .9rem;
    font-weight: 400;

    position: relative;
    top: 29%;
}

.right-container{
    grid-area: right;
}

.right-top-container{
    background-color: hsl(248, 32%, 49%);
    border-radius: .5rem;
    height: 11.5%;
    margin: auto auto 1.5rem auto;
    box-shadow: 0px 6px 1px rgba(0, 0, 0, .2);
}

.top-text-special{
    color: white;
    font-weight: 600;
    font-size: .85rem;

    position: relative;
    top: 50%;
    left: 72%;
    transform: translate(-50%, -50%);
}

.top-text{
    color: white;
    font-weight: 400;
}

.right-form{
    background-color: white;
    height: 23rem;
    border-radius: .5rem;
    padding: 1.5rem;
    padding-top: 2.5rem;
    box-shadow: 0 7px 1px rgba(0, 0, 0, .15);

    display: grid;
    grid-template-areas: 
    "fname"
    "lname"
    "email"
    "password"
    "submit-btn"
    "bottom-text";
}

input{
    font-family: 'Poppins', sans-serif;
    font-weight: 500;
    font-size: .8rem;

    position: relative;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    padding: 0 0 0 1.5rem;

    height: 130%;
    width: 90%;

    border: solid;
    border-width: .09rem;
    border-radius: .4rem;
    border-color: hsl(246, 25%, 77%);
}

.first-name-div{
    grid-area: fname;
    margin: 0 0 7% 0;

    position: relative;
}

.last-name-div{
    grid-area: lname;
    margin: 0 0 7% 0;

    position: relative;
}

.email-div{
    grid-area: email;
    margin: 0 0 7% 0;

    position: relative;
}

.password-div{
    grid-area: password;
    margin: 0 0 7% 0;

    position: relative;
}

.submit-btn-div{
    grid-area: submit-btn;
}

#submit-btn{
    position: relative;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 97.1%;
    height: 130%;
    border-radius: .4rem;

    background-color: hsl(154, 59%, 51%);
    border: none;
    color: white;
    box-shadow: 0 2px .5px rgba(0, 0, 0, .4);

    cursor: pointer;
}

.right-footer-text{
    grid-area: bottom-text;
}

.footer-text{
    position: relative;
    top: 50%;
    left: 58%;
    transform: translate(-50%, -50%);

    color: grey;
    font-size: .7rem;
    font-weight: 600;
}

.footer-span{
    color: hsl(0, 100%, 74%);
}

#error-img{
    position: absolute;
    top: 6px;
    right: 22px;
}

.hidden{
    display: none;
}

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>FrontEndMentor#3</title>
    <link rel="stylesheet" href="styles.css">
    <link rel="shortcut icon" href="images/favicon-32x32.png" type="image/x-icon">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">

</head>
<body>
    <div class="container">
        <div class="left-container">
            <h1 class="left-heading">Learn to code by <br>
                 watching others</h1>
            <p class="left-content">See how experienced developers solve problems in real-time. <br>
                Watching scripted tutorials is great, but understanding how <br>
                developers think is invaluable.</p>
        </div>

        <div class="right-container">
            <div class="right-top-container">
                <p class="top-text-special">Try it free 7 days <span class="top-text">then $20/mo. thereafter</span></p>
            </div>
            <form action="#" class="form">
                <div class="right-form">
                    <div class="first-name-div">
                        <input type="text" name="fname" id="first-input" placeholder="First Name">
                        <img class="error-img hidden" src="images/icon-error.svg" alt="错误图标">
                    </div>
                    <div class="last-name-div">
                        <input type="text" name="lname" id="last-input" placeholder="Last Name">
                        <img class="error-img hidden" src="images/icon-error.svg" alt="错误图标">
                    </div>
                    <div class="email-div">
                        <input type="email" name="email-address" id="email" placeholder="example@email.com">
                        <img class="error-img hidden" src="images/icon-error.svg" alt="错误图标">
                    </div>
                    <div class="password-div">
                        <input type="password" name="password" id="password" placeholder="Password">
                        <img class="error-img hidden" src="images/icon-error.svg" alt="错误图标">
                    </div>
                    <div class="submit-btn-div">
                        <button type="submit" id="submit-btn">CLAIM YOUR FREE TRIAL</button>
                    </div>
                    <div class="right-footer-text">
                        <p class="footer-text">By clicking the button, you are agreeing to our <span class="footer-span">Terms and Services</span></p>
                    </div>
                </div>
            </form>
        </div>
    </div>
    <script src="index.js"></script>
</body>
</html>

问题分析与修复

核心错误原因

  1. inputs是类数组集合,不能直接取value:getElementsByTagName返回的是HTMLCollection,不是单个元素,必须遍历每个输入框才能获取对应的值。
  2. errorImg是类数组集合,不能直接调用classList:querySelectorAll返回的是NodeList,同样需要针对每个输入框对应的错误图标操作。

修复后的JavaScript代码

"use strict"

const form = document.querySelector(".form");
const inputs = document.getElementsByTagName("input");
const errorImgs = document.querySelectorAll(".error-img");
const submitBtn = document.getElementById("submit-btn");

// 邮箱格式验证正则
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

submitBtn.addEventListener("click", (e) => {
    e.preventDefault();

    // 遍历每个输入框,对应各自的错误图标
    Array.from(inputs).forEach((input, index) => {
        const errorImg = errorImgs[index];
        let isValid = true;

        // 验证空值
        if (!input.value.trim()) {
            isValid = false;
        }

        // 针对邮箱输入框做格式验证
        if (input.type === 'email' && !emailRegex.test(input.value.trim())) {
            isValid = false;
        }

        // 控制错误图标显示/隐藏
        if (!isValid) {
            errorImg.classList.remove("hidden");
        } else {
            errorImg.classList.add("hidden");
        }
    });
});

额外修复点

  1. CSS闭合问题:原CSS中.hidden规则未闭合,已补充}。
  2. HTML表单结构:原代码中form标签提前闭合,已调整为包裹整个表单内容,避免结构错误。

内容的提问来源于stack exchange,提问作者A Barlow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:01:00