news 2026/4/20 3:01:06

Web前端制作一个评论发布案例

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Web前端制作一个评论发布案例

完成该案例需要用到的知识点有:

一、HTML基础

1. 语义化标签使用: textarea 多行输入框、 ul/li 列表承载动态内容、 span 行内元素展示字数/操作按钮

2. 表单属性: maxlength 限制输入框最大字符数、 placeholder 输入提示

3. 元素标识: id 用于精准获取DOM元素, class 用于样式控制和类名判断

二、CSS基础&布局

1. 通用样式重置: * {margin:0;padding:0;box-sizing:border-box;} 统一盒模型、清除默认边距

2. 布局技巧: flex 布局实现头像+内容的横向排列、 float 实现字数统计与发布按钮的右对齐; flex-shrink:0 防止头像被挤压

3. 样式控制: resize:none 禁止文本域拉伸、 cursor:pointer/not-allowed 鼠标样式交互、 disabled 状态的样式覆写

4. 辅助样式: word-break:break-all 实现长文本自动换行、 dashed 虚线边框做列表分隔、 border-radius:50% 实现圆形头像

5. 溢出处理: overflow:hidden 清除浮动带来的父元素高度塌陷问题

三、JavaScript 核心(重点)

1. DOM 元素操作

- 元素获取: document.getElementById() 根据ID获取指定DOM元素(核心获取方式)

- 元素创建: document.createElement() 动态创建节点(如li)

- 内容插入: innerHTML 为元素设置HTML结构(支持拼接标签字符串,高效创建复杂节点); insertBefore(新节点, 参考节点) 实现新内容前置插入(发布的内容显示在最顶部)

- 元素删除: parentElement.remove() 通过子元素找到父元素并删除整个节点

- 内容重置:通过修改元素 value (文本域)、 textContent (普通元素)实现内容清空/更新

2. 事件处理

- 事件绑定: addEventListener() 为元素绑定事件(推荐方式,可绑定多个同类型事件)

- 核心事件类型: input 事件(文本域实时输入监听,区别于 keyup ,兼容粘贴/输入法等场景); click 点击事件(发布、删除操作)

- 事件委托:将删除事件绑定在父元素(ul) 上,通过事件对象 e.target 判断触发源(是否为删除按钮 .the_del ),解决动态生成元素无法绑定事件的问题

- 事件对象: e.target 获取事件的实际触发元素,通过 classList.contains() 判断元素是否包含指定类名

3. 数据处理与交互

- 文本处理: trim() 去除字符串首尾空格,避免发布空内容/纯空格内容

- 状态控制:通过修改元素 disabled 属性,控制发布按钮的可用/禁用状态(无内容时禁用,有内容时启用)

- 随机数应用: Math.floor(Math.random() * 数组长度) 实现从数组中随机选取元素(随机获取用户头像和昵称)

- 日期时间格式化: new Date() 获取当前时间,通过 getFullYear()/getMonth()/getDate() 等方法获取时间分量; padStart(2, '0') 实现补零操作(如1月→01月,9分→09分),保证时间格式统一

4. 数组与对象基础

- 数组取值:通过索引获取数组中的对象元素(如 userList[索引] )

- 对象属性访问:通过 . 访问对象的属性(如 randomUser.uname / randomUser.imgSrc )

5. 页面初始化

- 初始状态设置:页面加载时,主动设置发布按钮的 disabled = true ,避免初始状态按钮可点击的不合理情况

6. 字符串拼接

- 模板字符串(隐式):通过 ${变量} 拼接HTML结构和动态数据(昵称、头像、时间、发布内容),简化字符串拼接操作

四、代码的实现

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>微博发布</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } ul { list-style: none; } .w { width: 900px; margin: 0 auto; } .controls { overflow: hidden; margin-top: 20px; } .controls p { color: #409eff; margin-bottom: 8px; font-size: 16px; } .controls textarea { width: 100%; height: 120px; resize: none; border: 1px solid #e4e7ed; border-radius: 8px; outline: none; padding: 12px; font-size: 16px; } .controls div { float: right; margin-top: 10px; } .controls div span { color: #666; font-size: 14px; } .controls div .useCount { color: red; } .controls div button { width: 80px; outline: none; border: none; background: #0088ff; height: 32px; cursor: pointer; color: #fff; font-size: 14px; border-radius: 4px; margin-left: 10px; } .controls div button:hover { background: #0066cc; } .controls div button:disabled { background: #a0cfff; cursor: not-allowed; } .contentList { margin-top: 40px; } .contentList li { padding: 16px 0; border-bottom: 1px dashed #e4e7ed; position: relative; display: flex; gap: 12px; } .contentList li .userpic { width: 48px; height: 48px; border-radius: 50%; flex-shrink: 0; } .contentList li .content-wrap { flex: 1; } .contentList li .username { font-size: 14px; font-weight: 500; color: #303133; margin-bottom: 4px; display: block; } .contentList li .send-time { font-size: 12px; color: #909399; margin-bottom: 8px; display: block; } .contentList li .content { font-size: 14px; color: #606266; line-height: 1.5; word-break: break-all; } .contentList li .the_del { position: absolute; right: 0; top: 16px; font-size: 18px; cursor: pointer; color: #909399; } </style> </head> <body> <div class="w"> <div class="controls"> <p>有什么新鲜事想告诉大家?</p> <textarea placeholder="说点什么吧..." id="area" cols="30" rows="10" maxlength="200"></textarea> <div> <span class="useCount" id="useCount">0</span> <span>/</span> <span>200</span> <button id="send">发布</button> </div> </div> <div class="contentList"> <ul id="list"></ul> </div> </div> <script> // 模拟用户数据 const userList = [ { uname: '司马懿', imgSrc: '../image/图1.png' }, { uname: '女娲', imgSrc: '../image/图2.png' }, { uname: '百里守约', imgSrc: '../image/图3.png' }, { uname: '亚瑟', imgSrc:'../image/图4.png' }, { uname: '虞姬', imgSrc: '../image/图5.png' }, { uname: '张良', imgSrc: '../image/图6.png' }, { uname: '安其拉', imgSrc: '../image/图7.png' }, { uname: '李白', imgSrc: '../image/图8.jpg' }, { uname: '阿珂', imgSrc: '../image/图9.jpg' }, { uname: '墨子', imgSrc: '../image/图10.jpg' }, ]; // DOM元素 const area = document.getElementById('area'); const useCount = document.getElementById('useCount'); const sendBtn = document.getElementById('send'); const list = document.getElementById('list'); // 1. 实时更新字数统计 area.addEventListener('input', function () { const len = this.value.trim().length; useCount.textContent = len; // 控制发布按钮状态 sendBtn.disabled = len === 0; }); // 2. 发布评论 sendBtn.addEventListener('click', function () { const content = area.value.trim(); if (!content) return; // 随机选择一个用户作为评论者 const randomUser = userList[Math.floor(Math.random() * userList.length)]; // 获取当前时间 const now = new Date(); const timeStr = `${now.getFullYear()}年${(now.getMonth() + 1).toString().padStart(2, '0')}月${now.getDate().toString().padStart(2, '0')}日 ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`; // 创建评论元素 const li = document.createElement('li'); li.innerHTML = ` <img class="userpic" src="${randomUser.imgSrc}" alt="${randomUser.uname}"> <div class="content-wrap"> <span class="username">${randomUser.uname}</span> <span class="send-time">发布于 ${timeStr}</span> <div class="content">${content}</div> </div> <span class="the_del">×</span> `; // 添加到列表最前面 list.insertBefore(li, list.firstElementChild); // 清空输入框并重置字数 area.value = ''; useCount.textContent = '0'; sendBtn.disabled = true; }); // 3. 删除评论 list.addEventListener('click', function (e) { if (e.target.classList.contains('the_del')) { e.target.parentElement.remove(); } }); // 初始化按钮状态 sendBtn.disabled = true; </script> </body> </html>

五、代码效果呈现

代码效果如下图所示:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 23:40:03

从零实现电商搜索:Elasticsearch整合SpringBoot详解

以下是对您提供的博文《从零实现电商搜索:Elasticsearch整合SpringBoot详解》的 深度润色与重构版本 。本次优化严格遵循您的全部要求: ✅ 彻底去除AI腔、模板化结构(如“引言/总结/展望”等机械标题) ✅ 打破模块割裂,以真实开发者的视角重构逻辑流:从一个具体问题切…

作者头像 李华
网站建设 2026/4/18 10:57:17

Open Interpreter语音识别:音频处理脚本部署实战

Open Interpreter语音识别&#xff1a;音频处理脚本部署实战 1. Open Interpreter 是什么&#xff1f;不只是“会写代码的AI” 你有没有试过这样操作电脑&#xff1a; “把这段录音转成文字&#xff0c;再按时间戳分段&#xff0c;最后导出成带格式的 Word 文档。” ——不是…

作者头像 李华
网站建设 2026/4/18 5:38:18

避坑指南:部署阿里Paraformer时常见问题全解,少走弯路

避坑指南&#xff1a;部署阿里Paraformer时常见问题全解&#xff0c;少走弯路 1. 为什么需要这份避坑指南&#xff1f; 你是不是也经历过这些时刻&#xff1a; 模型跑起来了&#xff0c;但上传个MP3就卡住不动&#xff0c;控制台一片空白&#xff1f;热词明明填了“人工智能…

作者头像 李华
网站建设 2026/4/16 10:08:49

Glyph功能测评:图文混合理解到底强不强

Glyph功能测评&#xff1a;图文混合理解到底强不强 1. 这不是OCR&#xff0c;也不是普通多模态模型 很多人第一次看到Glyph&#xff0c;会下意识把它当成一个“高级OCR工具”——毕竟它把文字渲染成图、再让视觉模型去读。但这种理解偏差很大&#xff0c;就像把显微镜当成放大…

作者头像 李华
网站建设 2026/4/17 14:29:56

AI看图说话怎么实现?Qwen视觉模型部署实战教程

AI看图说话怎么实现&#xff1f;Qwen视觉模型部署实战教程 1. 什么是真正的“AI看图说话”&#xff1f; 你有没有试过把一张照片发给朋友&#xff0c;然后问&#xff1a;“这张图里有什么&#xff1f;”——现在&#xff0c;这个动作可以直接交给AI来完成。但“看图说话”不是…

作者头像 李华
网站建设 2026/4/16 17:01:47

Clawdbot直连Qwen3-32B教程:Ollama模型注册+Clawdbot配置+Web测试全链路

Clawdbot直连Qwen3-32B教程&#xff1a;Ollama模型注册Clawdbot配置Web测试全链路 1. 为什么需要这条链路&#xff1a;从本地大模型到可用聊天界面 你是不是也遇到过这样的情况&#xff1a;好不容易在本地跑起了Qwen3-32B这个性能强劲的320亿参数模型&#xff0c;结果只能对着…

作者头像 李华