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

textarea输入后submit按钮仍无法启用的技术问题求助

问题:文本框输入内容后提交按钮仍保持禁用状态

我有一个包含textarea和submit按钮的表单,需求是根据textarea内是否有输入来启用或禁用submit按钮,已确认能够正确选中submit按钮与textarea元素。当前使用Django框架,相关代码如下:

JS代码

document.addEventListener('DOMContentLoaded',() => {

    document.querySelector('#all-posts').addEventListener('click', () => loadAllPosts())
    if (document.querySelector('#following') != null){
        document.querySelector('#following').addEventListener('click', () => loadFollowing())
    }

    loadAllPosts();
});

function loadAllPosts(){

    document.querySelector('#allPosts-view').style.display = 'block';
    document.querySelector('#following-view').style.display = 'none';

    fetch('/api/post')
    .then(response => response.json())
    .then(data => {
        const posts = data.data.posts;
        const postCards = posts.map(post => {
            let likeBtnClass = 'fa fa-heart-o';
            if (post.liked_by_user) {
                likeBtnClass = 'fa fa-heart';
            }
            const on = new Date(post.posted_on).toLocaleString('en-US', { 
                hour: 'numeric',
                minute: 'numeric', 
                month: 'long', 
                day: 'numeric', 
                year: 'numeric', 
                timeZone: 'UTC' 
            });
            return `
                <div class="card text-white bg-dark mb-3" style="margin-bottom: 5px;">
                    <div class="card-body">
                        <h5 class="card-title">${post.posted_by.username}</h5>
                        <p class="card-subtitle mb-2 text-muted" style="font-size: 12px;">${on}</p>
                        <hr style="border: none; height: 1px; background-color: #FFFFF0; margin: 0px;">
                        <p class="card-text" style="margin-top: 5px; font-size: 25px;">${post.content}</p>
                        <div class="like-container">
                            <i id="like-btn" class="${likeBtnClass}" style="font-size:24px; cursor:pointer; margin-right: 10px;"></i>
                            <p class="card-subtitle mb-2 text-muted" style="margin-top: 0.5rem; padding: 0px; font-size: 12px;">${post.likes}</p>
                        </div>
                    </div>
                </div>
            `;
        });
        document.querySelector('#allPosts-view').innerHTML += postCards.join('');
    })
    .catch(err => console.error(err));

    const likeBtnsContainer = document.querySelector('#allPosts-view');
    likeBtnsContainer.addEventListener('click', (event) => {
    if (event.target.matches('#like-btn')) {
        event.target.classList.toggle('fa-heart');
        event.target.classList.toggle('fa-heart-o');
    }
    });

    if (document.querySelector('#newPost-form') !== null) {
        const submit = document.querySelector('#newPost-submit');
        const content = document.querySelector('#newPost-content');

        submit.disabled = true;
      
        content.addEventListener('keyup', () => {
          if (content.value.length > 0) {
            submit.disabled = false;
          } else {
            submit.disabled = true;
          }
        });
    }
      
}


function loadFollowing() {

    document.querySelector('#allPosts-view').style.display = 'none';
    document.querySelector('#following-view').style.display = 'block';
}

HTML代码

{% extends "network/layout.html" %}
{% load static %}

{% block title %} Index {% endblock %}
{% block js %} <script src="{% static 'network/index.js' %}"></script> {% endblock %}

{% block body %}
    <div id="allPosts-view">
        {% if request.user.is_authenticated %}
        <div class="card text-white bg-dark mb-3" style="padding: 15px; margin-bottom: 5px;" >
            <form id="newPost-form">
                <div class="form-group">
                    <label for="NEW-POST" style="font-size: 20px;">New Post</label>
                    <hr style="border: none; height: 1px; background-color: #FFFFF0; margin: 0px 0px 15px 0px;">
                    <textarea class="form-control" id="newPost-content" rows="3" style="resize: none; height: 120px;"></textarea>
                </div>
                <input id="newPost-submit" type="submit" class="btn btn-primary" style="background-color: #007BFF;" value="Post">
            </form>
        </div>
        {% endif %}
    </div>

    <div id="following-view">
    </div>
{% endblock %}

问题现象

submit按钮初始状态已设置为禁用,但在textarea中输入内容后,按钮仍处于禁用状态,无法正常启用。


解决方案

问题核心是DOM元素被覆盖导致事件监听失效,加上事件类型选择不够全面,以下是修复后的代码和说明:

修复后的JS代码

document.addEventListener('DOMContentLoaded',() => {
    document.querySelector('#all-posts').addEventListener('click', () => loadAllPosts())
    if (document.querySelector('#following') != null){
        document.querySelector('#following').addEventListener('click', () => loadFollowing())
    }

    // 单独初始化表单监听,避免被后续DOM操作影响
    initFormListener();
    loadAllPosts();
});

// 抽离表单监听逻辑
function initFormListener() {
    const form = document.querySelector('#newPost-form');
    if (!form) return;

    const submit = form.querySelector('#newPost-submit');
    const content = form.querySelector('#newPost-content');

    // 初始化禁用状态(排除纯空格情况)
    submit.disabled = !content.value.trim();

    // 使用input事件,覆盖粘贴、拖拽等所有输入场景
    content.addEventListener('input', () => {
        // 判断是否为有效输入(非纯空格)
        submit.disabled = content.value.trim().length === 0;
    });
}

function loadAllPosts(){
    document.querySelector('#allPosts-view').style.display = 'block';
    document.querySelector('#following-view').style.display = 'none';

    // 先保存表单容器,避免被innerHTML覆盖
    const formContainer = document.querySelector('#newPost-form')?.parentElement;

    fetch('/api/post')
    .then(response => response.json())
    .then(data => {
        const posts = data.data.posts;
        const postCards = posts.map(post => {
            let likeBtnClass = 'fa fa-heart-o';
            if (post.liked_by_user) {
                likeBtnClass = 'fa fa-heart';
            }
            const on = new Date(post.posted_on).toLocaleString('en-US', { 
                hour: 'numeric',
                minute: 'numeric', 
                month: 'long', 
                day: 'numeric', 
                year: 'numeric', 
                timeZone: 'UTC' 
            });
            return `
                <div class="card text-white bg-dark mb-3" style="margin-bottom: 5px;">
                    <div class="card-body">
                        <h5 class="card-title">${post.posted_by.username}</h5>
                        <p class="card-subtitle mb-2 text-muted" style="font-size: 12px;">${on}</p>
                        <hr style="border: none; height: 1px; background-color: #FFFFF0; margin: 0px;">
                        <p class="card-text" style="margin-top: 5px; font-size: 25px;">${post.content}</p>
                        <div class="like-container">
                            <i class="like-btn ${likeBtnClass}" style="font-size:24px; cursor:pointer; margin-right: 10px;"></i>
                            <p class="card-subtitle mb-2 text-muted" style="margin-top: 0.5rem; padding: 0px; font-size: 12px;">${post.likes}</p>
                        </div>
                    </div>
                </div>
            `;
        });

        const allPostsView = document.querySelector('#allPosts-view');
        // 先清空容器
        allPostsView.innerHTML = '';
        // 把表单放回容器顶部
        if (formContainer) {
            allPostsView.appendChild(formContainer);
        }
        // 再追加帖子内容
        allPostsView.innerHTML += postCards.join('');
    })
    .catch(err => console.error(err));

    const likeBtnsContainer = document.querySelector('#allPosts-view');
    likeBtnsContainer.addEventListener('click', (event) => {
        // 修正重复id问题,改用class选择器
        if (event.target.matches('.like-btn')) {
            event.target.classList.toggle('fa-heart');
            event.target.classList.toggle('fa-heart-o');
        }
    });
}


function loadFollowing() {
    document.querySelector('#allPosts-view').style.display = 'none';
    document.querySelector('#following-view').style.display = 'block';
}

关键修改说明

  1. 分离表单监听逻辑:将表单的事件绑定放在initFormListener函数中,在DOM加载完成后直接执行,避免被loadAllPosts里的DOM操作覆盖。
  2. 更换事件类型:用input事件替代keyup,覆盖粘贴、拖拽文本等所有输入场景,同时用trim()判断内容是否为有效输入(排除纯空格的无效内容)。
  3. 避免DOM元素被覆盖:在loadAllPosts中先保存表单的父元素,清空容器后重新添加表单,再追加帖子内容,保证原表单DOM不被替换,事件监听持续有效。
  4. 修正重复ID问题:原代码中所有点赞按钮使用相同的id="like-btn",违反HTML规范,改为class选择器.like-btn,避免事件绑定冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 19:24:57