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

Node.js中点击博客删除按钮报错,for循环访问元素返回undefined

Node.js无刷新删除博客报错问题排查与解决

问题描述

我是Node.js初学者,制作了blogs.ejs页面展示登录用户的博客文章,添加删除锚点以实现无刷新删除功能,使用fetch向后端发送POST请求。但每次点击删除按钮都会报错,控制台无输出,排查发现for循环中访问元素时每次返回undefined,不清楚问题所在。

相关代码

blogs.ejs代码

<!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>Document</title>
    <link rel="stylesheet" href="/css/home.css" />
    
</head>
<body>
    <div class="flex-box">
        <div class="nav-content"> Welcome <%= user.name %></div>
            <div></div>
            <div></div>
            <div class="nav-content"><a href="/home/<%= user._id %>">Home</a></div>
            <div class="nav-content"><a href="/myblogs/<%= user._id %>">My blogs</a></div>
            <div class="nav-content"><a href="/addblogs/<%= user._id %>">Add blog</a></div>
        </div>
        <br>
        <div>
            <p class="user_id" style="display:none"><%= user._id %></p>
            <h2 class="blog-name">My Blogs</h2>
        </div>
        <br>
        
        <% if(blogs.length!=0){ %>
            <% blogs.forEach(blog=>{ %>
                <div class="blog-content">
                    <div class="blog">
                        <a  class="delete" data-doc="<%= blog._id %>">Delete</a>
                        <p class="id" style="display:none ;"><%= blog._id %></p>
                        <h3><%= blog.title %></h3>
                        <p><%= blog.post %></p>
                    </div>
                </div>
                <br><br>
            <% }) %>
        <% }else{%>
            <h3>No blog Posts</h3>
        <% } %>
        <br><br>
    </div>
    
    <script>
        const deleted =document.querySelectorAll('a.delete');
            for(var i=0;i<deleted.length;i++){
                deleted[i].addEventListener('click',function(){
                    // Accessing post id
                    var id=document.getElementsByClassName('id')[i].innerHTML;
                    const usr_id=document.getElementsByClassName('user_id')[0].innerHTML;
                    console.log("In script tag: post id is "+id)
                    const url='/delete';
                        customHeaders = { "Content-Type": "application/json", }
                        let data={
                            post_id:id,
                            usr_id:usr_id
                        };
                        fetch(url,{
                            method:'POST',
                            body:JSON.stringify(data),
                            headers:customHeaders,
                        }).then((res) =>{
                            res.json();
                            console.log("Method passed")
                        })
                        .then((data)=>{
                            console.log(data);
                        })
                        .catch((err) => 
                            console.log(err))
                        })
            }
    </script>

    
</body>
</html>

routes.js代码

router.post('/delete',async(req,res)=>{
    const id=req.body.id;
    const user=req.body.usr_id;
    console.log("In routes.js: post id is "+id);
    try{
        await Post.deleteOne({_id:id});
        console.log("deleted");
        res.json({redirect:'/'})

    }
    catch(err){
       console.log(err);
    }
})

问题分析与解决

1. 循环变量作用域导致undefined

用var声明的i是函数级作用域,循环结束后i的值会变成deleted.length,点击事件触发时,document.getElementsByClassName('id')[i]访问超出数组长度的索引,直接返回undefined。

解决方式:

  • 把var i改成let i,let是块级作用域,每次循环会创建独立的变量:
for(let i=0;i<deleted.length;i++){
    // 原逻辑保留
}
  • 或者用forEach遍历删除按钮,写法更简洁:
deleted.forEach(btn => {
    btn.addEventListener('click', function() {
        // 后续逻辑
    })
})

2. 简化博客ID获取逻辑

你已经给删除按钮加了data-doc="<%= blog._id %>"属性,直接通过按钮自身就能拿到ID,不用再查找同级的.id元素:

const id = this.getAttribute('data-doc');

3. 修复后端参数接收错误

前端发送的参数是post_id,但后端代码里取的是req.body.id,导致后端拿到的id是undefined。修改后端代码:

const id = req.body.post_id; // 改为匹配前端的参数名

4. 补全fetch的then链返回值

第一个then里调用res.json()但没有返回,导致第二个then接收的data是undefined,需要加上return:

.then((res) =>{
    console.log("Method passed")
    return res.json(); // 返回解析后的JSON数据
})

修改后的完整代码示例

前端脚本修改版

const deleted = document.querySelectorAll('a.delete');
deleted.forEach(btn => {
    btn.addEventListener('click', function() {
        const id = this.getAttribute('data-doc');
        const usr_id = document.getElementsByClassName('user_id')[0].innerHTML;
        console.log("In script tag: post id is " + id);
        const url = '/delete';
        const customHeaders = { "Content-Type": "application/json", }
        let data = {
            post_id: id,
            usr_id: usr_id
        };
        fetch(url, {
            method: 'POST',
            body: JSON.stringify(data),
            headers: customHeaders,
        }).then((res) => {
            console.log("Method passed")
            return res.json();
        })
        .then((data) => {
            console.log(data);
            // 删除成功后移除页面上对应的博客元素
            this.closest('.blog-content').remove();
        })
        .catch((err) => {
            console.log(err);
        })
    })
})

后端代码修改版

router.post('/delete', async(req, res) => {
    const id = req.body.post_id; // 修正参数名
    const user = req.body.usr_id;
    console.log("In routes.js: post id is " + id);
    try {
        await Post.deleteOne({ _id: id });
        console.log("deleted");
        res.json({ redirect: '/', success: true })
    } catch (err) {
        console.log(err);
        res.status(500).json({ error: err.message }); // 向前端返回错误信息
    }
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 02:40:50