【react案例】实现评论列表

news2024/11/19 18:25:08

1. 需求

在这里插入图片描述

  1. 展示评论列表
  2. 实现删除功能
    2.1 只有自己的评论才展示删除按钮
    2.2 点击删除按钮,删除当前评论
  3. tab切换(点击对应tab,对tab文案高亮处理)
  4. 评论高亮
  5. 评论排序(最新、最热)

2. 实现思路

  1. useState维护评论列表
  2. map方法遍历渲染
  3. 删除显示——条件渲染
  4. 删除功能——拿到当前评论项的id,然后对原有评论列表进行过滤,根据id剔除要删除的评论项
  5. tab高亮——记录点击的tab的type,根据type去匹配高亮样式
  6. 评论排序——根据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: '二郎神'
  }
  // tab
  const 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教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2166268.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于vue框架的大同传统文化非物质文化宣传管理系统jzo9d(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,非遗类型,文化遗产 开题报告内容 基于Vue框架的大同传统文化非物质文化宣传管理系统开题报告 一、研究背景 在全球化加速的今天&#xff0c;传统文化的保护与传承面临着前所未有的挑战。大同&#xff0c;作为中国历史文化名城&a…

职场能力强的人都在做什么---今日头条

【职场里,能力强的人都在做哪些事... - 今日头条】https://m.toutiao.com/is/ikn6kt9q/ 知识雷达 2024-09-21 16:33 目录 职场里,能力强的人都在做哪些事呢? 1、复盘; 2、多角度思考;3、记录信息; 4、永远积极主动;5、主动获取信息差; 6、明确人和人的关系;7、…

STM32杂项

STM32杂项 1.启动过程2.中断3.GPIO4.Systick5.串口printf6.独立看门狗 记录单片机在工作中遇到的问题和特殊情况。 1.启动过程 M3/M4/M7内核复位后&#xff0c;做的第一件事&#xff1a; 1.从地址0x0000 0000处取出堆栈指针MSP的初始值&#xff0c;该值就是栈顶地址。 2.从地址…

2024必备中英互译利器全知道

现在英语目前还是学习最广泛的第二语言&#xff0c;所以很多资料都有英文的版本。如果外语不好&#xff0c;那中英互译翻译工具就能帮我们解决这个问题。今天我们一起来探讨下有哪些好用的翻译工具。 1.福昕在线翻译 链接直达>>https://fanyi.pdf365.cn/doc 这个工具…

【linux】进度条

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;linux笔记仓 目录 01.屏幕缓冲区换行&#xff08;LF, \n&#xff09;和回车&#xff08;CR, \r&#xff09;换行回车在屏幕缓冲区中的作用代码块1&#xff1a;代码块2&#xff1a; 02.进度条优化版…

SpringBoot3+Swagger3(最新版springdoc-openapi教程)

第一步&#xff1a;引入springdoc-openapi依赖 <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId><version>2.6.0</version></dependency> 第二步&#xff1a; 配置…

打开ffmpeg编码器的时候报错:avcodec_open2()返回-22

[h264_v4l2m2m 0x555555617a00] Could not find a valid device [h264_v4l2m2m 0x555555617a00] cant configure encoder 前言&#xff1a;先做一个操作&#xff0c;查找编码器的时候&#xff0c;使用名字查找的方式&#xff1a; const AVCodec *avcodec_find_encoder_by_n…

ubuntu数据硬盘故障导致系统启动失败

背景&#xff1a; 系统盘损坏或者/etc/fatab误修改导致开机启动挂载失败系统无法启动 解决方法 重启

BFS 解决最短路径问题, 迷宫中离入口最近的出口,最小基因变化,单词接龙,为高尔夫比赛砍树

文章目录 1926. 迷宫中离入口最近的出口433. 最小基因变化127. 单词接龙675. 为高尔夫比赛砍树 1926. 迷宫中离入口最近的出口 边权为1的最短路径问题 我们要知道上下左右都是可以走的 &#xff08;用队列&#xff09;走过的地方不要在走了&#xff0c;这样会进入死循环&#x…

零信任内网安全访问

随着互联网的持续发展&#xff0c;便捷的共享方式极大地提高了企业的生产力和工作效率&#xff0c;但随之也给企业内网带来了极大的安全隐患。企业内网承载大量的核心资产和机密数据&#xff0c;一旦受到攻击可能会造成大量损失&#xff0c;因此&#xff0c;如何通过零信任内网…

快手一面:给定一棵二叉树,要求将其转换为其镜像?

目录标题 题解&#xff1a;二叉树的镜像&#xff08;Invert Binary Tree&#xff09;问题描述示例解题思路代码实现详细分析复杂度分析优点注意事项&#x1f495; 题解&#xff1a;二叉树的镜像&#xff08;Invert Binary Tree&#xff09; 问题描述 给定一棵二叉树&#xff…

探索AI新纪元:揭秘Mammoth库的神秘面纱

文章目录 探索AI新纪元&#xff1a;揭秘Mammoth库的神秘面纱背景&#xff1a;为何选择Mammoth&#xff1f;简介&#xff1a;Mammoth是什么&#xff1f;安装&#xff1a;如何获取Mammoth&#xff1f;使用&#xff1a;Mammoth的基本函数场景应用&#xff1a;Mammoth在实际中的运用…

基于Python大数据的B站热门视频的数据分析及可视化系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

宠物空气净化器和普通的空气净化器有区别吗?哪款能吸猫毛

这不是国庆节要来了吗&#xff0c;想着假期变多了可以多陪一下自家的小猫咪&#xff0c;但是也怕猫咪的毛发太多让我产生退缩的念头。 刚开始养的时候&#xff0c;我就知道猫咪是会掉毛的&#xff0c;毕竟猫咪的毛发这么旺盛&#xff0c;掉毛也是正常的&#xff0c;但是我似乎…

SpringCloud源码:客户端分析(二)- 客户端源码分析

背景 我们继续分析EurekaClient的两个自动化配置类&#xff1a; 自动化配置类功能职责EurekaClientAutoConfiguration配置EurekaClient确保了Eureka客户端能够正确地&#xff1a;- 注册到Eureka服务端- 周期性地发送心跳信息来更新服务租约- 下线时通知Eureka服务端- 获取服务实…

Qt网络编程——QUdpSocket

文章目录 Qt网络编程QUdpSocketUdp回显服务器Udp客户端 Qt网络编程 网络编程本质上是写应用层代码&#xff0c;需要传输层提供支持。 而传输层最核心的协议就是UDP和TCP&#xff0c;这两个协议有较大差别&#xff0c;所以Qt提供了两套API。 要是有Qt网络编程的API&#xff0…

9.23-9.25学习

前置知识 docker&#xff1a;Docker-CSDN博客 docker安装mysql和 redis&#xff1a;https://blog.csdn.net/weixin_73118927/article/details/142530243?fromshareblogdetail&sharetypeblogdetail&sharerId142530243&sharereferPC&sharesourceweixin_7311892…

从预测性维护到智能物流:ARM边缘计算控制器的工业实践

工业4.0时代的到来&#xff0c;边缘计算技术成为连接物理世界与数字世界的桥梁。ARM架构的边缘计算控制器凭借其低功耗、高能效和灵活性等特点&#xff0c;在工业自动化领域展现出巨大潜力。本文将通过几个实际应用案例来探讨ARM边缘计算控制器是如何提升生产线效率和安全性的&…

03DSP学习-利用syscfg配置IO

上一篇博客介绍了syscfg&#xff0c;对syscfg有了初步的了解&#xff0c;但是在真正使用上它之前&#xff0c;还不能理解他是一个神器。 (在写博客的时候&#xff0c;我是在从头到尾重新完成这个步骤&#xff0c;希望对初学者有点帮助) 找到Board Component 打开syscfg文件&…

【Tourism】Yuncheng(4)

文章目录 1、永乐宫&#xff08;AAAA&#xff09;2、寿圣寺3、城隍庙4、池神庙 1、永乐宫&#xff08;AAAA&#xff09; 永乐宫&#xff0c;原名大纯阳万寿宫&#xff0c;位于山西省运城市芮城县以北约三公里处的龙泉村东&#xff0c;是为纪念八仙之一吕洞宾而修建的一座道教宫…