1. 需求
- 展示评论列表
- 实现删除功能
2.1 只有自己的评论才展示删除按钮
2.2 点击删除按钮,删除当前评论 - tab切换(点击对应tab,对tab文案高亮处理)
- 评论高亮
- 评论排序(最新、最热)
2. 实现思路
- useState维护评论列表
- map方法遍历渲染
- 删除显示——条件渲染
- 删除功能——拿到当前评论项的id,然后对原有评论列表进行过滤,根据id剔除要删除的评论项
- tab高亮——记录点击的tab的type,根据type去匹配高亮样式
- 评论排序——根据tab的type对评论列表状态数据进行不同的排序处理,当成新值传给set方法重新渲染视图UI(注意:排序后不要修改评论列表状态数据的原始值,教程里推荐使用lodash包的orderBy方法)
3. 代码
- 样式是我自己随便写的,具体可以参考b站本身的css样式
3.1 App.js
import { useState } from "react"
import _ from 'lodash'
import './App.css'function App() {// 评论列表const initReviewList = [{rid: 2,user: {uid: '002',avator: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.gC14cncyeUsZYKNwXOyBtgHaHa?rs=1&pid=ImgDetMain',uname: '小猫爱吃鱼'},content: '喵喵喵',ctime: '09-22 17:55',like: 90},{rid: 1,user: {uid: '001',avator: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.qCys2C8LjF8c3_UHbGOooAAAAA?rs=1&pid=ImgDetMain',uname: '小狗爱吃骨头'},content: '汪汪汪',ctime: '09-22 14:55',like: 100},{rid: 0,user: {uid: '000',avator: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.pL9aeO50HMujMSzGcOPhKwAAAA?rs=1&pid=ImgDetMain',uname: '二郎神'},content: '666',ctime: '09-30 12:23',like: 88}]// 当前登录的用户信息const user = {uid: '000',avator: 'https://tse4-mm.cn.bing.net/th/id/OIP-C.pL9aeO50HMujMSzGcOPhKwAAAA?rs=1&pid=ImgDetMain',uname: '二郎神'}// tabconst tabs = [{type: 'hot',text:'最热',},{type: 'new',text:'最新',}]const [reviewList, setReviewList] = useState(_.orderBy(initReviewList, 'like', 'desc'))function handleDeleteReview(currentRid) {setReviewList(reviewList.filter(item=> item.rid !== currentRid))}const [currTabType, steCurrTabType] = useState('hot')function handleClickTab(type) {steCurrTabType(type)if (type === 'hot') {// 根据点赞数量,降序排序setReviewList(_.orderBy(reviewList, 'like', 'desc'))} else {// 根据评论时间,降序排序setReviewList(_.orderBy(reviewList, 'ctime', 'desc'))}}return (<div className="App">{/* 导航栏 */}<div className="review-header">{/* 标题 */}<div className="review-title-container"><span className="review-title">评论</span>{/* 评论总数 */}<div className="review-total">{reviewList.length ?? 0}</div></div><div className="review-tabs-container">{tabs.map((item, index) => {return <div key={item.type} className="tabs-item"><span className={`tabs-text ${item.type === currTabType && 'tabs-active'}`} onClick={() => handleClickTab(item.type)}>{item.text}</span>{index < tabs.length - 1 && <div className="tabs-idot">|</div>}</div>})}</div></div>{/* 评论 */}<div className="review-wrap">{/* 发表评论 */}<div className="box-normal"><img className="normal-avator" src={user.avator}></img><input className="review-input" placeholder="发一条友善的评论"></input><button className="add-review">发布</button></div>{/* 评论列表 */}<div className="review-list">{reviewList.map((item) => {{/* 每一条评论 */ }return <div className="review-item" key={item.rid}>{/* 头像 */}<img className="review-avator" src={item.user.avator}></img><div className="review-item-content">{/* 用户名 */}<div className="user-name">{item.user.uname}</div>{/* 评论内容 */}<span className="review-content">{item.content}</span>{/* 评论相关信息 */}<div className="review-msg">{/* 评论时间 */}<span className="review-date">{item.ctime}</span>{/* 点赞数量 */}<span className="good-count">点赞数:{item.like}</span>{/* 删除评论按钮 */}{item.user.uid === user.uid && <span className="review-delete" onClick={() => handleDeleteReview(item.rid)}>删除</span>}</div>{/* 分割线 */}<div className="part-line"></div></div></div>})}</div></div></div>);
}export default App;
3.2 App.css
.review-header {display: flex;.review-title-container {display: flex;align-items: center;margin-right: 40px;.review-title {font-weight: bold;margin-right: 2px;}.review-total {font-size: 12px;color: gray;}}.review-tabs-container {display: flex;align-items: center;font-size: 12px;font-weight: bold;.tabs-item {color: gray;display: flex;.tabs-text {cursor: pointer;}.tabs-active {color: black;}.tabs-idot {margin: 0px 5px;}}}
}.box-normal {display: flex;margin: 16px 0px 30px 0px;.normal-avator {width: 50px;height: 50px;border-radius: 50%;margin-right: 20px;}.review-input {border: 1px solid #F1F2F3;background-color: #F1F2F3;border-radius: 6px;padding-left: 10px;}.add-review {background-color: skyblue;border: transparent;border-radius: 6px;color: #fff;margin-left: 6px;padding: 0px 10px;}
}.review-list {.review-item {display: flex;margin-bottom: 15px;.review-avator {width: 50px;height: 50px;border-radius: 50%;margin-right: 20px;}.review-item-content {.user-name {font-size: 12px;font-weight: bold;color: gray;margin-bottom: 6px;}.review-content {font-size: 14px;}.review-msg {font-size: 10px;color: gray;.review-date {margin-right: 15px;}.good-count {margin-right: 15px;}.review-delete {cursor: pointer;}}.part-line {margin-top: 5px;height: 0.5px;background-color: #E3E5E7;}}}
}
3.3 效果图
参考
黑马程序员react教程