完成该案例需要用到的知识点有:
一、HTML基础
-
语义化标签使用: textarea 多行输入框、 ul/li 列表承载动态内容、 span 行内元素展示字数/操作按钮
-
表单属性: maxlength 限制输入框最大字符数、 placeholder 输入提示
-
元素标识: id 用于精准获取DOM元素, class 用于样式控制和类名判断
二、CSS基础&布局
-
通用样式重置: * {margin:0;padding:0;box-sizing:border-box;} 统一盒模型、清除默认边距
-
布局技巧: flex 布局实现头像+内容的横向排列、 float 实现字数统计与发布按钮的右对齐; flex-shrink:0 防止头像被挤压
-
样式控制: resize:none 禁止文本域拉伸、 cursor:pointer/not-allowed 鼠标样式交互、 disabled 状态的样式覆写
-
辅助样式: word-break:break-all 实现长文本自动换行、 dashed 虚线边框做列表分隔、 border-radius:50% 实现圆形头像
-
溢出处理: overflow:hidden 清除浮动带来的父元素高度塌陷问题
三、JavaScript 核心(重点)
- DOM 元素操作
-
元素获取: document.getElementById() 根据ID获取指定DOM元素(核心获取方式)
-
元素创建: document.createElement() 动态创建节点(如li)
-
内容插入: innerHTML 为元素设置HTML结构(支持拼接标签字符串,高效创建复杂节点); insertBefore(新节点, 参考节点) 实现新内容前置插入(发布的内容显示在最顶部)
-
元素删除: parentElement.remove() 通过子元素找到父元素并删除整个节点
-
内容重置:通过修改元素 value (文本域)、 textContent (普通元素)实现内容清空/更新
- 事件处理
-
事件绑定: addEventListener() 为元素绑定事件(推荐方式,可绑定多个同类型事件)
-
核心事件类型: input 事件(文本域实时输入监听,区别于 keyup ,兼容粘贴/输入法等场景); click 点击事件(发布、删除操作)
-
事件委托:将删除事件绑定在父元素(ul) 上,通过事件对象 e.target 判断触发源(是否为删除按钮 .the_del ),解决动态生成元素无法绑定事件的问题
-
事件对象: e.target 获取事件的实际触发元素,通过 classList.contains() 判断元素是否包含指定类名
- 数据处理与交互
-
文本处理: trim() 去除字符串首尾空格,避免发布空内容/纯空格内容
-
状态控制:通过修改元素 disabled 属性,控制发布按钮的可用/禁用状态(无内容时禁用,有内容时启用)
-
随机数应用: Math.floor(Math.random() * 数组长度) 实现从数组中随机选取元素(随机获取用户头像和昵称)
-
日期时间格式化: new Date() 获取当前时间,通过 getFullYear()/getMonth()/getDate() 等方法获取时间分量; padStart(2, '0') 实现补零操作(如1月→01月,9分→09分),保证时间格式统一
- 数组与对象基础
-
数组取值:通过索引获取数组中的对象元素(如 userList[索引] )
-
对象属性访问:通过 . 访问对象的属性(如 randomUser.uname / randomUser.imgSrc )
- 页面初始化
- 初始状态设置:页面加载时,主动设置发布按钮的 disabled = true ,避免初始状态按钮可点击的不合理情况
- 字符串拼接
- 模板字符串(隐式):通过 ${变量} 拼接HTML结构和动态数据(昵称、头像、时间、发布内容),简化字符串拼接操作
四、代码的实现
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>
五、代码效果呈现
代码效果如下图所示:
