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

作品集网站板块切换报错求助:TypeError无法读取className

作品集网站板块切换功能报错修复

问题现象

实现作品集网站板块切换功能,初期运行正常,后续出现崩溃,抛出错误:

app.js:10 Uncaught TypeError: Cannot read properties of undefined (reading 'className') at HTMLDivElement. (app.js:10:53)

原始代码

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>Portfolio</title>
    <link rel="stylesheet" href="styles/styles.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
    <script src="https://kit.fontawesome.com/25c3cf235c.js" crossorigin="anonymous"></script>
</head>
<body class="main-content">
    <header class="section sec1 header active" id="home"></header>
    <main>
        <section class="section sec2 about" id="about"></section>
        <section class="section sec3 portfolio" id="portfolio"></section>
        <section class="section sec4 blogs" id="blogs"></section>
        <section class="section sec5 contact" id="contact"></section>
    </main> 

    <div class="controlls">
        <div class="control control-1 active-btn" data-id="home">
            <i class="fa-solid fa-house-user"></i>
        </div>
        <div class="control control-2" data-id="about">
            <i class="fa-solid fa-user"></i>
        </div>
        <div class="control control-3" data-id="portfolio">
            <i class="fa-solid fa-briefcase"></i>
        </div>
        <div class="control control-4" data-id="blogs">
            <i class="fa-solid fa-newspaper"></i>
        </div>
        <div class="control control-5" data-id="contact">
            <i class="fa-solid fa-envelope"></i>
        </div>
    </div>

    <script src="app.js"></script>
</body>
</html>

CSS

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    list-style: none;
}

:root {
    --color-primary: #191d2b;
    --color-secondary: #27AE60;
    --color-white: #FFFFFF;
    --color-black: #000;
    --color-grey0: #f8f8f8;
    --color-grey-1: #dbe1e8;
    --color-grey-2: #b2becd;
    --color-grey-3: #6c7983;
    --color-grey-4: #454e56;
    --color-grey-5: #2a2e35;
    --color-grey-6: #12181b;
    --br-sm-2: 14px;
    --box-shadow-1: 0 3px 15px rgba(0,0,0,.3);
}

body {
    font-family: 'Poppins', sans-serif;
    background-color: var(--color-primary);
    font-size: 1.1rem;
    color: var(--color-white );
    transition: all .4s ease-in-out;
}

a {
    display: inline-block;
    text-decoration: none;
    color: inherit;
    font-family: inherit;
}

header {
    height: 100vh;
    color: var(--color-white);
    overflow: hidden;
}

section {
    min-height: 100vh;
    width: 100%;
    position: absolute;
    left: 0;
    top: 0;
    padding: 3rem 18rem;
}

.section {
    transform: translateY(-100%) scale(0);
    transition: all .4 ease-in-out;
    background-color: var(--color-primary);
}

.sec1 {
    display: none;
    transform: translateV(0) scale(1);
    background-color: rgb(26, 22, 50);
}

.sec2 {
    display: none;
    transform: translateV(0) scale(1);
    background-color: slateblue;
}

.sec3 {
    display: none;
    transform: translateV(0) scale(1);
    background-color: rgb(127, 123, 151);
}
.sec4 {
    display: none;
    transform: translateV(0) scale(1);
}

.sec5 {
    display: none;
    transform: translateV(0) scale(1);
}

.controlls {
    position: fixed;
    z-index: 10;
    top: 50%;
    right: 3%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    transform: translateY(-50%);
    .active-btn {
        background-color: var(--color-secondary) !important;
        transition: all .4s ease-in-out;
        i {
            color: var(--color-white) !important;
        }
    }
    .control {
        padding: 1rem;
        cursor: pointer;
        background-color: var(--color-grey-4);
        width: 55px;
        height: 55px;
        border-radius: 50%;
        display: flex;
        justify-content: center;
        align-items: center;
        margin: .7rem 0;
        box-shadow: var(--box-shadow-1);
        i {
            font-size: 1.2rem;
            color: var(--color-grey-2);
            pointer-events: none;
        }
    }
}

JavaScript

const sections = document.querySelectorAll('.section');
const sectBtns = document.querySelectorAll(".controlls");
const sectBtn = document.querySelectorAll(".control");
const allSections = document.querySelector('.main-content');

function PageTransitions() {
    for (let i = 0; i < sectBtn.length; i++) {
        sectBtn[i]. addEventListener("click", function() {
            let currentBtn = document.querySelectorAll('.active-btn');
            currentBtn[0].className = currentBtn[0].className.replace('active-btn','');
            this.className += 'active-btn';
        })
    }

    allSections.addEventListener('click', (e)=> {
        const id = e.target.dataset.id;
        if (id) {
            sectBtns.forEach((btn) => {
                btn.classList.remove('active')
            })

            e.target.classList.add('active')

            sections.forEach((section)=> {
                section.classList.remove('active')
            })

            const element = document.getElementById(id);
            element.classList.add('active');
        }
    }) 
}

PageTransitions();

错误原因

  1. 类名操作不规范:直接拼接className += 'active-btn'会重复添加类名,多次点击后document.querySelectorAll('.active-btn')可能返回多个元素或空数组,访问currentBtn[0]会得到undefined,触发读取className的错误。
  2. 事件委托的目标偏差:给body绑定点击事件,点击按钮内部的<i>标签时,e.target指向<i>而非按钮,此时e.target.dataset.id不存在,后续获取element为undefined,操作classList也会报错。
  3. CSS显示逻辑冲突:CSS中用.sec1等类直接控制display,而JS操作.active类,两者功能重叠,导致板块切换逻辑混乱。

修复方案

修复后的JavaScript

const sections = document.querySelectorAll('.section');
const sectBtns = document.querySelectorAll(".controlls .control");
const allSections = document.querySelector('.main-content');

function PageTransitions() {
    // 为每个控制按钮绑定点击事件
    sectBtns.forEach(btn => {
        btn.addEventListener("click", function() {
            // 移除所有按钮的active-btn类
            sectBtns.forEach(b => b.classList.remove('active-btn'));
            // 给当前点击的按钮添加active-btn类
            this.classList.add('active-btn');
            
            // 获取目标板块ID
            const targetId = this.dataset.id;
            if (targetId) {
                // 隐藏所有板块
                sections.forEach(section => section.classList.remove('active'));
                // 显示目标板块
                const targetSection = document.getElementById(targetId);
                if (targetSection) {
                    targetSection.classList.add('active');
                }
            }
        });
    });
}

PageTransitions();

修复后的CSS关键部分

.section {
    transform: translateY(-100%) scale(0);
    transition: all .4s ease-in-out;
    background-color: var(--color-primary);
    display: none; /* 默认隐藏所有板块 */
}

/* 激活状态的板块显示 */
.section.active {
    display: block;
    transform: translateY(0) scale(1);
}

/* 保留各板块的背景色设置 */
.sec1 {
    background-color: rgb(26, 22, 50);
}

.sec2 {
    background-color: slateblue;
}

.sec3 {
    background-color: rgb(127, 123, 151);
}

修复说明

  1. 标准化类名操作:使用classList.add()和classList.remove()替代直接修改className,避免重复添加类名,同时确保操作的可靠性。
  2. 避免事件目标偏差:直接给每个控制按钮绑定事件,不再通过父元素委托,确保点击时目标始终是按钮本身,不会触发到内部图标。
  3. 统一显示逻辑:用.active类统一控制板块的显示/隐藏,删除原始CSS中.sec1等类的display和transform属性,消除逻辑冲突。
  4. 增加存在性检查:获取目标板块后先判断是否存在,再执行类名操作,防止undefined报错。

内容的提问来源于stack exchange,提问作者Chin-Erdene Gantulga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:50:31