完善评论发布功能
完善评论发布功能
效果如下:
一、HTML结构搭建
首先规划评论功能的模块,包括输入区域、发布按钮、字数统计和评论列表。
<!-- 发布区域 --><div class="wrapper"><i class="avatar"></i><textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea><button>发布</button></div><!-- 字数统计 --><div class="wrapper"><span class="total">0/200字</span></div><!-- 楼层 --><div class="list container"><div class="item" style="display: none;"><i class="avatar"></i><div class="info"><p class="name"></p><p class="text"></p><p class="time"></p></div></div></div>
- 输入区采用flex布局,让头像、输入框、按钮横向排列
- 限制textarea的最大长度(
maxlength="200"
),避免输入内容过长 - 评论列表使用容器包裹,方便后续动态添加新评论
二 、发布功能
1. 字数统计功能
实时显示输入字数,并在无内容时隐藏统计信息:
const text = document.querySelector('textarea');
const count = document.querySelector('.total');text.addEventListener('input', function() {// 显示字数统计count.style.opacity = 1;count.textContent = `${this.value.length}/200字`;// 无内容时隐藏统计if (this.value.length === 0) {count.style.opacity = 0;}
});
- 监听input事件,实时获取输入内容长度
- 通过opacity控制统计信息的显示/隐藏
2. 创建评论元素
封装一个函数,动态生成评论DOM结构,便于重复调用:
function createCommentElement() {// 创建外层容器const commentDiv = document.createElement('div');commentDiv.className = 'item'; // 复用已有样式// 创建头像const avatar = document.createElement('i');avatar.className = 'avatar';// 创建信息容器(包含用户名、内容、时间)const infoDiv = document.createElement('div');infoDiv.className = 'info';// 用户名const nameP = document.createElement('p');nameP.className = 'name';nameP.textContent = '清风徐来'; // 评论内容const textP = document.createElement('p');textP.className = 'text';textP.textContent = text.value; // 从输入框获取内容// 发布时间const timeP = document.createElement('p');timeP.className = 'time';timeP.textContent = new Date().toLocaleString(); // 本地化时间格式// 组装元素infoDiv.append(nameP, textP, timeP); // 批量添加子元素commentDiv.append(avatar, infoDiv);return commentDiv;
}
- 代码复用:每次发布评论都调用此函数,无需重复编写DOM操作
- 结构清晰:与HTML中预设的评论样式保持一致,避免样式错乱
3. 发布评论功能(按钮点击+回车发布)
支持两种发布方式:点击按钮发布、按Enter键发布:
const btn = document.querySelector('button');
const list = document.querySelector('.list');
//按键
btn.addEventListener('click', function () {const newCommet = createCommentElement();list.appendChild(newCommet);// item.style.display = 'block';reset();})
//点击text.addEventListener('keyup', function (e) {//判断按键类型if (e.key === 'Enter') {//避免空内容if (text.value.trim() !== '') {const newCommet = createCommentElement();list.appendChild(newCommet);}reset();}})
- 发布后清空输入框,并重置字数统计状态
- 回车发布时判断内容不为空
完整代码
<!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>评论回车发布</title><style>.wrapper {min-width: 400px;max-width: 800px;display: flex;justify-content: flex-end;}.avatar {width: 48px;height: 48px;border-radius: 50%;overflow: hidden;background: url(./images/avatar.jpg) no-repeat center / cover;margin-right: 20px;}.wrapper textarea {outline: none;border-color: transparent;resize: none;background: #f5f5f5;border-radius: 4px;flex: 1;padding: 10px;transition: all 0.5s;height: 30px;}.wrapper textarea:focus {border-color: #e4e4e4;background: #fff;height: 50px;}.wrapper button {background: #00aeec;color: #fff;border: none;border-radius: 4px;margin-left: 10px;width: 70px;cursor: pointer;}.gray {background-color: gray;}.wrapper .total {margin-right: 80px;color: #999;margin-top: 5px;opacity: 0;transition: all 0.5s;}.list {min-width: 400px;max-width: 800px;display: flex;}.list .item {width: 100%;display: flex;}.list .item .info {flex: 1;border-bottom: 1px dashed #e4e4e4;padding-bottom: 10px;}.list .item p {margin: 0;}.list .item .name {color: #FB7299;font-size: 14px;font-weight: bold;}.list .item .text {color: #333;padding: 10px 0;}.list .item .time {color: #999;font-size: 12px;}.container {display: flex;flex-direction: column;gap: 1rem;}</style>
</head><body><!-- 发布区域 --><div class="wrapper"><i class="avatar"></i><textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea><button>发布</button></div><!-- 字数统计 --><div class="wrapper"><span class="total">0/200字</span></div><!-- 楼层 --><div class="list container"><div class="item" style="display: none;"><i class="avatar"></i><div class="info"><p class="name"></p><p class="text"></p><p class="time"></p></div></div></div><script>const text = document.querySelector('.wrapper textarea');const btn = document.querySelector('.wrapper button');const count = document.querySelector('.wrapper .total');const list = document.querySelector('.list');const item = document.querySelector('.list .item');const speak = document.querySelector('.list .info .text');const time = document.querySelector('.list .info .time');function createCommentElement() {const commentDiv = document.createElement('div');commentDiv.className = 'item';const avatar = document.createElement('i');avatar.className = 'avatar';const infoDiv = document.createElement('div');infoDiv.className = 'info';const nameP = document.createElement('p');nameP.className = 'name';nameP.textContent = '清风徐来';const textP = document.createElement('p');textP.className = 'text';textP.innerHTML = text.value;const timeP = document.createElement('p');timeP.className = 'time';// 时间timeP.textContent = new Date().toLocaleString();// 放置元素infoDiv.appendChild(nameP);infoDiv.appendChild(textP);infoDiv.appendChild(timeP);commentDiv.appendChild(avatar);commentDiv.appendChild(infoDiv);return commentDiv;}function reset() {text.value = '';count.style.opacity = 0;count.innerHTML = '0/200字';}text.addEventListener('input', function () {count.style.opacity = 1;count.innerHTML = `${text.value.length}/200字`;// console.log(text.value.length);if (text.value.length === 0) {count.style.opacity = 0;}})btn.addEventListener('click', function () {const newCommet = createCommentElement();list.appendChild(newCommet);// item.style.display = 'block';reset();})text.addEventListener('keyup', function (e) {if (e.key === 'Enter') {if (text.value.trim() !== '') {const newCommet = createCommentElement();list.appendChild(newCommet);}reset();}})</script>
</body></html>