基于React实现B站评论区

news2024/12/24 21:09:32

        今天继续来学习一下React,使用React实现B站评论区,如下图:

        在使用React开发类似B站评论区的功能时,我们需要考虑以下几个关键点来构建一个基本的评论系统:

1. 设计组件结构

首先,设计组件结构是关键。至少需要以下几种组件:

  • CommentList: 负责展示评论列表。
  • Comment: 单个评论项的展示,包括用户名、评论内容、时间戳等。
  • CommentContent: 用户输入评论的内容,包括文本输入框和提交按钮。
  • User: 当前的登录的用户
  • TabList: 评论排序的导航类型

2. 管理状态

        使用React的状态管理功能(如useState或useReducer)来处理评论数据和表单输入状态。例如,可以创建一个状态来存储所有的评论数据,以及一个状态来管理评论表单的输入值。

3. 发送和获取评论

当然,本次实现不考虑连接后端,只利用假的数据来实现B站评论区的按照热度、事件排序展示、删除评论、发布评论。如果需要连接后端可以考虑下面你的操作:

获取评论:  如果评论数据来自后端API,可以使用fetch或第三方库如axios来获取数据,并在组件挂载时或根据需要触发请求。
发送评论: 当用户提交评论时,捕获表单数据并发送POST请求到后端API,成功后通常会刷新评论列表以显示新评论。
删除评论:当用户删除评论的时候,捕获评论Id并发送DELETE请求到后端API,后端根据ID删除该条评论。

4. 代码实现

import './App.scss'
import {useState} from "react";
import avatar1 from './images/1.png';
import avatar2 from './images/2.png';
import stukk from './images/lyy.jpg';

/**
 * 评论列表的渲染和操作
 *
 * 1. 根据状态渲染评论列表
 * 2. 删除评论
 * 3. 发布评论
 */

// 评论列表数据
const defaultList = [
    {
        // 评论id
        rpid: 3,
        // 用户信息
        user: {
            uid: '13258165',
            avatar: avatar1,
            uname: '周杰伦',
        },
        // 评论内容
        content: '哎哟,不错哦',
        // 评论时间
        ctime: '10-18 08:15',
        like: 98,
    },
    {
        rpid: 2,
        user: {
            uid: '36080105',
            avatar: avatar2,
            uname: '许嵩',
        },
        content: '我寻你千百度 日出到迟暮',
        ctime: '11-13 11:29',
        like: 88,
    },
    {
        rpid: 1,
        user: {
            uid: '30009257',
            avatar: stukk,
            uname: 'stu_kk',
        },
        content: '关注stu_kk',
        ctime: '10-19 09:00',
        like: 66,
    },
]
// 当前登录用户信息
const user = {
    // 用户id
    uid: '30009257',
    // 用户头像
    avatar: stukk,
    // 用户昵称
    uname: 'stu_kk',
}


/**
 * 导航 Tab 的渲染和操作
 *
 * 1. 渲染导航 Tab 和高亮
 * 2. 评论列表排序
 *  最热 => 喜欢数量降序
 *  最新 => 创建时间降序
 */

// 导航 Tab 数组
const tabs = [
    {type: 'hot', text: '最热', isActive: true},
    {type: 'time', text: '最新', isActive: false},
]

const App = () => {
    const [commentList, setCommentList] = useState(defaultList); // 评论列表
    const [tabList, setTabList] = useState(tabs); // 导航 Tab 数组
    const [commentContent, setCommentContent] = useState(''); // 评论内容
    const changeTabList = (id) => { //改变导航Tab
        const newTabList = tabList.map((item, index) => {
            if (index === id) {
                item.isActive = true;
            } else {
                item.isActive = false;
            }
            return item;
        });
        return newTabList;
    }

    const clickTab = (id) => { // 点击导航Tab
        const newCommentList = id === 0 ? commentList.sort((a, b) => b.like - a.like) : commentList.sort((a, b) => (
            b.ctime > a.ctime ? 1 : -1
        ));
        console.log(newCommentList)
        setCommentList(newCommentList);
        setTabList(changeTabList(id));
    }

    const sendComment = () => { //发布评论
        console.log(111)
        if (commentContent.trim() === '') {
            alert('评论内容不能为空');
            return;
        }
        const newCommentList = [
            {
                rpid: commentList.length + 1,
                user: user,
                content: commentContent,
                ctime: '12-19 09:00',
                like: 0,
            },
            ...commentList,
        ];
        setCommentList(newCommentList);
        setCommentContent('');
    }

    const deleteCommentById = (id) => { //根据Id删除自己的评论
        setCommentList(commentList.filter((item) => item.rpid !== id))
    }

    return (
        <div className="app">
            {/* 导航 Tab */}
            <div className="reply-navigation">
                <ul className="nav-bar">
                    <li className="nav-title">
                        <span className="nav-title-text">评论</span>
                        {/* 评论数量 */}
                        <span className="total-reply">{10}</span>
                    </li>
                    <li className="nav-sort">
                        {/* 高亮类名: active */}
                        {tabList.map((item,index) => (
                            <span onClick={()=>clickTab(index)} className={item.isActive ? 'nav-item active' : 'nav-item'}  key={item.type}>{item.text}</span>
                            ))}
                    </li>
                </ul>
            </div>

            <div className="reply-wrap">
                {/* 发表评论 */}
                <div className="box-normal">
                    {/* 当前用户头像 */}
                    <div className="reply-box-avatar">
                        <div className="bili-avatar">
                            <img className="bili-avatar-img" src={user.avatar} alt="用户头像"/>
                        </div>
                    </div>
                    <div className="reply-box-wrap">
                        {/* 评论框 */}
                        <textarea
                            className="reply-box-textarea"
                            placeholder="发一条友善的评论"
                            value={commentContent}
                            onChange={(e) => setCommentContent(e.target.value)}
                        />
                        {/* 发布按钮 */}
                        <div className="reply-box-send" onClick={sendComment}>
                            <div className="send-text" >发布</div>
                        </div>
                    </div>
                </div>
                {/* 评论列表 */}
                <div className="reply-list">
                    {/* 评论项 */}
                    {commentList.map(item => (
                        <div className="reply-item" key={item.rpid}>
                            {/* 头像 */}
                            <div className="root-reply-avatar">
                                <div className="bili-avatar">
                                    <img
                                        className="bili-avatar-img"
                                        alt=""
                                        src={item.user.avatar}
                                    />
                                </div>
                            </div>

                            <div className="content-wrap">
                                {/* 用户名 */}
                                <div className="user-info">
                                    <div className="user-name">{item.user.uname}</div>
                                </div>
                                {/* 评论内容 */}
                                <div className="root-reply">
                                    <span className="reply-content">{item.content}</span>
                                    <div className="reply-info">
                                        {/* 评论时间 */}
                                        <span className="reply-time">{item.ctime}</span>
                                        {/* 评论数量 */}
                                        <span className="reply-time">点赞数:{item.like}</span>
                                        {/*根据用户与当前用户对比,设置是否有权限删除*/}
                                        {item.user.uid === user.uid && <span className="delete-btn" onClick={() => deleteCommentById(item.rpid)}>删除</span> }
                                    </div>
                                </div>
                            </div>
                        </div>
                    ))}
                </div>
            </div>
        </div>
    )
}

export default App

5. 实现效果

6. 代码解释

        上面React代码实现了一个基础的评论区功能,包含评论列表的渲染、导航Tab切换(用于排序)、发布评论、以及删除自己的评论功能。下面是对代码的详细解析:
1. 数据初始化
        评论列表数据 (defaultList): 定义了初始的评论数据数组,每个评论对象包含了评论ID (rpid)、用户信息 (user)、评论内容 (content)、评论时间 (ctime) 和点赞数 (like)。
当前登录用户信息 (user): 包含用户ID、头像和用户名,用于识别和执行删除操作。
2. 状态管理

  • 使用 useState Hook 来管理组件状态:
  • commentList: 当前的评论列表。
  • tabList: 导航Tab的状态,包括类型、文本和是否激活。
  • commentContent: 用户在评论框中输入的内容。

3. 导航Tab功能

  • tabs: 定义了两个导航Tab选项:“最热”和“最新”,每个Tab都有一个类型 (type)、文本 (text) 和激活状态 (isActive)。
  • changeTabList: 函数用来改变Tab的激活状态。
  • clickTab: 处理Tab点击事件,根据选择的Tab类型对评论列表进行排序,并更新Tab的激活状态。

4. 发布评论
        sendComment: 用户点击“发布”按钮时调用此函数,检查评论内容是否为空,然后将新评论追加到评论列表的开头,并清空输入框。
5. 删除评论
        deleteCommentById: 根据评论ID从评论列表中删除对应的评论,仅允许用户删除自己发布的评论。
6. UI渲染

  • 导航Tab (reply-navigation): 渲染导航Tab,根据tabList的状态来决定哪个Tab被高亮显示。
  • 评论输入框和发布按钮: 用户可以在此输入评论内容并发布。
  • 评论列表 (reply-list): 根据commentList渲染评论项,每个评论项包含用户头像、用户名、评论内容、评论时间和删除按钮(如果当前登录用户是评论作者)。

7. 总结

        文章使用React构建了一个仿照B站基本的前端评论系统,实现了动态加载、排序、添加和删除评论的基本功能。通过React的状态管理和事件处理机制,实现了交互式的用户体验。但是在实际应用中,还需考虑与后端接口的交互、错误处理、分页加载、以及更复杂的用户交互逻辑。

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

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

相关文章

【数据结构】:链表的带环问题

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;数据结构 &#x1f337;追光的人&#xff0c;终会万丈光芒 前言&#xff1a; 链表的带环问题在链表中是一类比较难的问题&#xff0c;它对我们的思维有一个比较高的要求&#xff0c;但是这一类…

ThreeJS:Mesh网格与三维变换

Mesh网格 ThreeJS中&#xff0c;Mesh表示基于以三角形为多边形网格(polygon mesh)的物体的类&#xff0c;同时也作为其它类的基类。 通过Mesh网格&#xff0c;我们可以组合Geometry几何体与Material材质属性&#xff0c;在3D世界中&#xff0c;定义一个物体。例如&#xff1a;之…

Unity ParticleSystem 入门

概述 在项目的制作过程成&#xff0c;一定少不了粒子系统的使用吧&#xff0c;如果你想在项目粒子效果&#xff0c;那这部分的内容一定不要错过喔&#xff01;我添加了理解和注释更好理解一点&#xff01; 这次的内容比较多&#xff0c;右侧有目录&#xff0c;可以帮助快速导…

高中数学:三角函数公式汇总及推导

一、定义 常用三角函数值 参考&#xff1a; 三角函数定义 二、基本三角函数及相互关系 sinx cosx tanx cscx secx cotx 函数间相互关系 参考&#xff1a; cosx、sinx、tanx的函数图像与性质 secx、cscx、cotx函数图像及相关关系 三、诱导公式 口诀&#xff1a;奇变…

通信接口——时钟和信号

前言 所有接口只要抓住三个核心点就能分清&#xff1a;时钟同步和异步&#xff0c;时钟的来源&#xff0c;信号的传输方向。 一、时钟同步和异步 接口之间的交互方式存在多种形式&#xff0c;如果按照是否有公共时钟CLK的参与&#xff0c;可以分为同步传输和异步传输。 同步&…

C语言——队列的实现

队列按照先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;的原则管理数据。这意味着最先进入队列的元素会被最先移出&#xff0c;类似于排队等候服务的情况。队列通常有两个主要操作&#xff1a;入队&#xff08;enqueue&#xff09;&#xff0c;将元素添加…

DRF返回值源码分析

DRF返回值源码分析 1 返回值 在视图中定义finalize_response方法&#xff08;也可以用来判断是否异常&#xff09; 自定义异常 配置文件 # settings.py REST_FRAMEWORK {"EXCEPTION_HANDLER": utils.handlers.exception_handler # 自定义的exceptional_handler路…

Sarcasm detection论文解析 |利用对话语境进行讽刺分析

论文地址&#xff1a; 论文地址&#xff1a;Sarcasm Analysis Using Conversation Context | Computational Linguistics | MIT Press github地址&#xff1a;https://github.com/debanjanghosh/sarcasm_context Alex-Fabbri/deep_learning_nlp_sarcasm: code for deep learnin…

基于springboot实现公司日常考勤系统项目【项目源码+论文说明】

基于springboot实现公司日常考勤系统演示 摘要 目前社会当中主要特征就是对于信息的传播比较快和信息内容的安全问题&#xff0c;原本进行办公的类型都耗费了很多的资源、传播的速度也是相对较慢、准确性不高等许多的不足。这个系统就是运用计算机软件来完成对于企业当中出勤率…

debug的基本使用

1.简介   首先看下IDEA中Debug模式下的界面。 如下是在IDEA中启动Debug模式&#xff0c;进入断点后的界面&#xff0c;我这里是Windows&#xff0c;可能和Mac的图标等会有些不一样。就简单说下图中标注的8个地方&#xff1a; ① 以Debug模式启动服务&#xff0c;左边的一个按…

Redis运维篇-快速面试笔记(速成版)

文章目录 1. Redis的持久化1.1 RDB&#xff08;快照模式&#xff09;1.2 AOF 模式 2. Redis主从模型&#xff08;高可用&#xff09;2.1 Redis的主从复制2.2 Redis拓扑结构 3. Redis集群模式&#xff08;高并发&#xff09;3.1 Redis的Slots3.2 集群模式的常用命令3.3 多主多从…

win下vscode的vim切换模式的中英文切换

问题描述 在vscode中安装vim插件后&#xff0c;如果insert模式下完成输入后&#xff0c;在中文输入方式下按esc会发生无效输入&#xff0c;需要手动切换到英文。 解决方法 下载完成vscode并在其中配置vim插件下载github—im-select.exe插件&#xff08;注意很多博文中的gitcod…

Node.js -- express 框架

文章目录 1. express 使用2. 路由2.1 路由的使用2.2 获取请求报文参数2.3 获取路由参数2.4 路由参数练习 3. express 响应设置4. 中间件4.1 全局中间件4.2 路由中间件4.3 静态资源中间件 5. 获取请求体数据 body-parser6. 防盗链7. 路由模块化8. 模板引擎8.1 了解EJS8.2 列表渲…

InfluxDB安装使用介绍

1.介绍 InfluxDB是一个由InfluxData开发的开源时序型数据。它由Go写成&#xff0c;着力于高性能地查询与存储时序型数据。InfluxDB被广泛应用于存储系统的监控数据&#xff0c;IoT行业的实时数据等场景。 2.对常见关系型数据库&#xff08;MySQL&#xff09;的基础概念对比 1…

Spring Cloud——Circuit Breaker上篇

Spring Cloud——Circuit Breaker上篇 一、分布式系统面临的问题1.服务雪崩2.禁止服务雪崩故障 二、Circuit Breaker三、resilience4j——服务熔断和降级1.理论知识2.常用配置3.案例实战&#xff08;1&#xff09;COUNT_BASED&#xff08;计数的滑动窗口&#xff09;&#xff0…

UE4_Niagara_两个模型之间的粒子幻化

学习笔记&#xff0c;仅供参考&#xff01; 操作步骤&#xff1a; 1、新建niagara system&#xff0c;添加空的发射器&#xff0c;渲染改为网格体渲染器&#xff0c;网格体为1M_Cube. 2、创建粒子材质重载。 3、渲染网格体的材质设置&#xff1a; 4、在发射器属性面板&#x…

LeetCode 213 —— 打家劫舍 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题是 LeetCode 198—— 打家劫舍 的升级版&#xff0c;多了一个首尾相连的设定。 因为首尾相连&#xff0c;所以第一个房屋和最后一个房屋只能偷窃其中一个。 所以&#xff0c;第一种方案就是不偷窃最后一个房…

Web APIs 学习归纳6--- BOM浏览器对象

前面几节主要针对DOM进行了学习&#xff0c;现在开始新的内容的学习---DOM浏览器对象。 DOM是更注重页面&#xff08;document&#xff09;内容的设计&#xff0c;但是BOM不仅限于页面&#xff08;document&#xff09;的设计&#xff0c;而是更加全面包括页面的刷新&#xff0…

SpringBoot使用ResponseBodyAdvice和RequestBodyAdvice实现请求体解密、响应体加密

文章目录 一、写在前面二、实现细节1、定义加解密注解2、请求体解密逻辑3、响应体加密逻辑4、测试类5、测试结果 三、源码分析1、RequestResponseBodyMethodProcessor2、RequestBodyAdvice3、ResponseBodyAdvice 一、写在前面 项目中经常需要对接第三方平台&#xff0c;每次对…

redis ZRANGE 使用最详细文档

环境&#xff1a; redis_version:7.2.2 本文参考 redis 官方文档1 语法 ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]参数含义key是有序集合的键名start stop在不同语境下&#xff0c;可用值不一样BYSCORE | BYLEX按照分数查询 | 相…