JavaScript更新对象数组后无重复渲染评论列表实现方法
评论区增量渲染实现方案
问题背景
开发评论功能时的基础逻辑:
- 定义了存储默认评论的对象数组,页面首次加载时渲染数组内的已有评论
- 搭建了支持输入姓名、评论内容的表单,点击提交按钮会将新评论通过
unshift插入数组头部 - 预期交互逻辑:
- 页面初始加载展示1条默认评论
- 第一次提交后,展示最新提交的评论+原有评论,共2条
- 第二次提交后,展示最新评论+此前的2条评论,共3条,以此类推
- 现存问题:直接调用原有全量渲染函数
generateCommentRows()会重复渲染已有内容,目前靠先清空容器再全量重渲染实现效果,需要实现不重跑全量渲染、直接增量更新DOM的方案。
原有代码
1. 评论数组定义
const commentsArray = [ { name: "Barack Obama", pfp: "./assets/images/image.jpg", date: "02/17/2021", comment: "blah blah", } ];
2. 原全量渲染函数
const generateCommentsRows = () => { commentsArray.forEach((event) => { const commentContainer = document.createElement("article"); commentContainer.classList.add("comments__area__lower__row"); const nameEl = document.createElement("p"); nameEl.classList.add("comments__area__lower__row__name"); nameEl.innerText = event.name; const pfpEl = document.createElement("img"); pfpEl.classList.add("comments__area__lower__row__pfp"); pfpEl.src = event.pfp; const dateEl = document.createElement("p"); dateEl.classList.add("comments__area__lower__row__date"); dateEl.innerText = event.date; const commentsEl = document.createElement("p"); commentsEl.classList.add("comments__area__lower__row__comments"); commentsEl.innerText = event.comment; commentContainer.appendChild(pfpEl); commentContainer.appendChild(nameEl); commentContainer.appendChild(dateEl); commentContainer.appendChild(commentsEl); const lowerCommentsArea = document.querySelector(".comments__area__lower"); lowerCommentsArea.appendChild(commentContainer); }); }; generateCommentsRows();
3. 原表单提交逻辑
const pushData = (event) => { let comments = { name: document.getElementById("name").value, pfp: "./assets/images/image.jpg", date: Date.now(), comment: document.getElementById("commentText").value, }; commentsArray.unshift(comments); }; let myBtn = document.getElementById("submitBtn"); myBtn.onclick = function () { pushData(); };
实现方案
核心逻辑:新评论始终插入数组头部,因此不需要遍历整个数组重绘所有已有评论,只需要单独生成新评论对应的DOM节点,直接插入评论容器的最顶部即可,完全不改动已经渲染完成的旧评论节点。
具体修改步骤
- 抽离单条评论的DOM生成逻辑,避免重复写相同的DOM创建代码,同时提前缓存评论容器的DOM引用,减少不必要的DOM查询:
// 提前缓存评论容器,不用每次操作DOM都重新查询 const lowerCommentsArea = document.querySelector(".comments__area__lower"); /** * 生成单条评论对应的DOM节点 * @param {object} commentData 单条评论数据 * @returns {HTMLElement} 评论节点 */ const createCommentElement = (commentData) => { const commentContainer = document.createElement("article"); commentContainer.classList.add("comments__area__lower__row"); const nameEl = document.createElement("p"); nameEl.classList.add("comments__area__lower__row__name"); nameEl.innerText = commentData.name; const pfpEl = document.createElement("img"); pfpEl.classList.add("comments__area__lower__row__pfp"); pfpEl.src = commentData.pfp; const dateEl = document.createElement("p"); dateEl.classList.add("comments__area__lower__row__date"); dateEl.innerText = commentData.date; const commentsEl = document.createElement("p"); commentsEl.classList.add("comments__area__lower__row__comments"); commentsEl.innerText = commentData.comment; commentContainer.appendChild(pfpEl); commentContainer.appendChild(nameEl); commentContainer.appendChild(dateEl); commentContainer.appendChild(commentsEl); return commentContainer; };
- 改造原有全量渲染函数,仅在页面初始化时调用一次,渲染默认评论:
const generateCommentsRows = () => { commentsArray.forEach(comment => { lowerCommentsArea.appendChild(createCommentElement(comment)); }); }; // 页面初始化仅执行一次全量渲染 generateCommentsRows();
- 修改提交逻辑,新评论入数组后,仅生成新评论对应的DOM,通过
prepend方法插入到评论容器最顶部,完成增量渲染:
const pushData = () => { const newComment = { name: document.getElementById("name").value.trim(), pfp: "./assets/images/image.jpg", date: new Date().toLocaleDateString(), // 替换原Date.now(),直接显示格式化日期,和默认评论格式一致 comment: document.getElementById("commentText").value.trim(), }; // 可选:增加空值校验,避免提交空评论 if (!newComment.name || !newComment.comment) return; commentsArray.unshift(newComment); // 增量插入新评论节点,不改动已有DOM lowerCommentsArea.prepend(createCommentElement(newComment)); // 提交后清空输入框 document.getElementById("name").value = ""; document.getElementById("commentText").value = ""; }; const myBtn = document.getElementById("submitBtn"); myBtn.onclick = pushData;
方案优势
- 没有全量重绘的开销,评论量越大性能优势越明显
- 抽离的单条评论生成逻辑可复用,后续修改评论项结构只需要改一处代码
- 逻辑和数组操作顺序完全匹配:
unshift往数组头加数据,prepend往容器头加节点,不会出现顺序错乱问题
内容的提问来源于stack exchange,提问作者amputator
相关产品推荐
相关产品推荐

