评论发布完整篇(react版)
此篇文章阐述评论的最新、最热之间的tab标签切换(包括当前所在tab标签的高亮显示问题);当前评论的删除;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序,点赞数量越多,此条评论越靠前;最新tab标签页所展示的内容是根据当前评论发布时间来进行排序,随着时间的推移,此条评论越靠前。
话不多说,上代码:
1.安装必要插件
classnames、dayjs、lodash、node-sass、sass-loader、uuid、lodash
安装命令如下:
classnames:npm install classnames或者 yarn add classnames
dayjs:npm install dayjs 或者 yarn add dayjs
lodash:npm install lodash 或者 yarn add lodash
安装scss相关包:npm install sass、npm install sass-resources-loader
uuid:npm install uuid或者 yarn add uuid
lodash:npm install lodash或者 yarn add lodash
安装好后可到package.json中查看相应版本信息

2.App.scss文件
.app {
width:100%;
height: 100%;
}
.reply-navigation{
.nav-bar{
list-style: none;
display: flex;
text-align: center;
height:20px;
line-height: 20px;
.nav-title{
margin-right:30px;
.nav-title-text{
font-size:25px;
font-weight: 700;
}
}
.nav-sort{
color:darkgray;
.nav-item{
width:35px;
cursor: pointer;
}
&>:first-child{
margin-right:35px;
border-right:2px solid darkgray;
padding-right:35px;
}
.active{
color:orange;
}
}
}
}
.reply-wrap{
height:100%;
background: url('./images/bg.jpg') no-repeat;
background-size: 100% 100%;
padding:20px;
.box-normal{
display: flex;
justify-content: flex-start;
margin-bottom: 20px;
.reply-box-avator{
.bili-avator{
width:80px;
height: 80px;
.bili-avator-img{
border-radius: 50%;
width:100%;
height: 100%;
}
}
}
.reply-box-wrap{
display: flex;
height: 80px;
margin-left:20px;
overflow: hidden;
.reply-box-textarea{
width: 400px;
margin-top: 15px;
height: 50px;
line-height: 50px;
text-align: center;
background-color:#E5E5E5;
}
.reply-box-send{
width:80px;
height: 55px;
line-height: 55px;
margin-top: 15px;
background-color: cornflowerblue;
color:#fff;
text-align: center;
margin-left:15px;
border-radius: 4px;
cursor: pointer;
.send-text{
font-size: 20px;
border: none;
}
}
}
}
.reply-list{
.reply-item{
width:100%;
height: 130px;
display: flex;
justify-content: flex-start;
margin-top:10px;
.root-reply-avator{
width:5%;
.bili-avator{
.bili-avator-img{
width:60px;
height:60px;
border-radius:50%;
}
}
}
.content-wrap{
width:95%;
overflow: hidden;
border-bottom: 2px solid darkgray;
.user-info{
.user-name{
font-size: 16px;
color:darkgray;
font-weight: 500;
}
}
.root-reply{
margin-top:25px;
.reply-content{
font-size: 20px;
color:chocolate;
font-weight: 700;
}
.reply-info{
font-size: 14px;
color:darkgray;
font-weight: 500;
margin-top:15px;
.reply-time{
margin-right:25px;
}
.reply-count{
margin-right:25px;
}
.reply-delete{
cursor: pointer;
}
.reply-delete:hover{
color:cornflowerblue;
}
}
}
}
}
}
}
3.App.js文件
import { useRef, useState } from 'react'
import './App.scss'
import avator from './images/avator.jpg'
import _ from 'lodash'
import classNames from 'classnames'
import { v4 as uuidV4 } from 'uuid'
import dayjs from 'dayjs'
//评论列表数据
const list = [
{
rpid: 1, //评论id
user: {
//用户信息
uid: '13258165',
avator: 'http://toutiao.itheima.net/resources/images/9.jpg',
uname: '周杰伦',
},
content: '哎呦,不错哦', //评论内容
ctime: '10-25 12:15', //评论时间
like: 88,
},
{
rpid: 2, //评论id
user: {
//用户信息
uid: '36080105',
avator: 'http://toutiao.itheima.net/resources/images/98.jpg',
uname: '许嵩',
},
content: '我寻你千百度,日出到迟暮', //评论内容
ctime: '04-12 08:45', //评论时间
like: 98,
},
{
rpid: 3, //评论id
user: {
//用户信息
uid: '30009257',
avator: 'http://toutiao.itheima.net/resources/images/56.jpg',
uname: '王心凌',
},
content: '或许失败过,但从未认输', //评论内容
ctime: '12-18 19:02', //评论时间
like: 120,
},
{
rpid: 4, //评论id
user: {
//用户信息
uid: '19858625',
avator: 'http://toutiao.itheima.net/resources/images/67.jpg',
uname: '徐凯',
},
content: '没有永远的敌人', //评论内容
ctime: '11-20 20:15', //评论时间
like: 120,
},
{
rpid: 5, //评论id
user: {
//用户信息
uid: '30009257',
avator: 'http://toutiao.itheima.net/resources/images/37.jpg',
uname: '杨幂',
},
content: '不只玫瑰有爱意', //评论内容
ctime: '07-20 20:15', //评论时间
like: 456,
},
{
rpid: 6, //评论id
user: {
//用户信息
uid: '30009257',
avator: 'http://toutiao.itheima.net/resources/images/28.jpg',
uname: '徐良',
},
content: '女骑士', //评论内容
ctime: '03-14 20:15', //评论时间
like: 253,
},
]
//当前登录用户信息
const user = {
//用户id
uid: '30009257',
//用户头像
avator,
//用户昵称
uname: '徐凯工作室',
}
//导航tab数组
const tabs = [
{ type: 'hot', text: '最热' },
{ type: 'time', text: '最新' },
]
const App = () => {
const [commentList, setCommentList] = useState(list)
//删除事件
const deleteHandle = (id) => {
//根据id删除
setCommentList(commentList.filter((item) => item.rpid !== id))
console.log(id)
}
//存储type
const [type, setType] = useState('hot')
//tabs标签切换事件,根据 type切换
const typeHandlerChange = (type) => {
setType(type)
console.log(type, '切换tab项')
if (type === 'time') {
//允许在集合commentList中,指定迭代函数ctime进行倒序排序desc
setCommentList(_.orderBy(commentList, 'ctime', 'desc'))
} else {
//允许在集合commentList中,指定迭代函数like进行倒序排序desc
setCommentList(_.orderBy(commentList, 'like', 'desc'))
}
}
const [content, setContent] = useState('')
const inputRef = useRef(null)
const sendHandler = () => {
setCommentList([
...commentList,
{
rpid: uuidV4(), //唯一识别id,通过uuid生成器产生随机id
user: {
//用户信息
uid: '30009257',
avator: 'http://toutiao.itheima.net/resources/images/28.jpg',
uname: '徐良',
},
content: content, //评论内容
ctime: dayjs(new Date()).format('MM-DD hh:mm'), //格式化 月-日 时:分
like: 253,
},
])
setContent('') //清空输入框内的值
inputRef.current.focus() //再次聚焦输入框
console.dir(inputRef.current)
}
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>
{/* 高亮类名:active */}
<li className="nav-sort">
{tabs.map((item) => (
<span
className={classNames('nav-item', {
active: type === item.type,
})}
key={item.type}
onClick={() => typeHandlerChange(item.type)}
>
{item.text}
</span>
))}
</li>
</ul>
</div>
<div className="reply-wrap">
{/* 发表评论 */}
<div className="box-normal">
{/* 当前用户头像 */}
<div className="reply-box-avator">
<div className="bili-avator">
<img
className="bili-avator-img"
alt="用户头像"
src={user.avator}
/>
</div>
</div>
<div className="reply-box-wrap">
{/* 评论框 */}
<textarea
className="reply-box-textarea"
placeholder="发一条友善的评论"
value={content}
onChange={(e) => {
setContent(e.target.value)
}}
ref={inputRef}
></textarea>
{/* 发布按钮 */}
<div className="reply-box-send">
<div className="send-text" onClick={sendHandler}>
发布
</div>
</div>
</div>
</div>
{/* 评论列表 */}
<div className="reply-list">
{/* 评论项 */}
{commentList.map((item) => (
<div className="reply-item" key={item.rpid}>
{/*头像 */}
<div className="root-reply-avator">
<div className="bili-avator">
<img
className="bili-avator-img"
alt=""
src={item.user.avator}
/>
</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-count">点赞数:{item.like}</span>
{/*删除 */}
{/*删除条件 */}
{user.uid === item.user.uid && (
<span
className="reply-delete"
onClick={() => {
deleteHandle(item.rpid)
}}
>
{'删除'}
</span>
)}
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
)
}
export default App
结果展示:

相关文章:
评论发布完整篇(react版)
此篇文章阐述评论的最新、最热之间的tab标签切换(包括当前所在tab标签的高亮显示问题);当前评论的删除;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序,点赞数量…...
前端window.open的简单使用
JavaScript 中的 Window.open() 用法详解-CSDN博客 window.open("https://www.baidu.com/?tn49055317_12_hao_pg", _blank);...
基于开源软件构建存储解决方案的思考
近来看了一些IBM的存储产品的资料,有一些收获。 依据存储软件和搭配硬件,IBM存储产品的组合,大致分类如下: 自研存储软件,搭配自研专有硬件自研存储软件,搭配通用服务器硬件,比如IBM Storage S…...
【leetcode】动态规划::前缀和(二)
标题:【leetcode】前缀和(二) 水墨不写bug 正文开始: (一) 和为K的子数组 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续…...
SpringBoot自动装配原理之@Import注解解析
文章目录 1. 概述2. 使用2.1 导入普通Bean2.2 导入配置类2.3 导入 ImportSelector 实现类2.4 导入 ImportBeanDefinitionRegistrar 实现类 3. 区别 1. 概述 当谈及现代Java开发领域中的框架选择时,SpringBoot无疑是无与伦比的热门之选。其简化了开发流程࿰…...
49 样式迁移【李沐动手学深度学习v2课程笔记】
1. 样式迁移(Style Transfer) 计算机视觉的应用之一,将样式图片中的样式(比如油画风格等)迁移到内容图片(比如实拍的图片)上,得到合成图片 可以理解成为一个滤镜,但相对于滤镜来讲…...
Linux的学习之路:4、权限
一、Linux权限的概念 权限我们都熟悉,最常见的就是在看电视时需要vip这个就是权限,然后在Linux就是有两个权限,就是管理员也就是超级用户和普通的用户 命令:su [用户名] 功能:切换用户。 例如,要从root用户…...
自定义类型—结构体
目录 1 . 结构体类型的声明 1.1 结构的声明 1.2 结构体变量的创建与初始化 1.3 结构体的特殊声明 1.4 结构体的自引用 2. 结构体内存对齐 2.1 对齐规则 2.2 为什么存在内存对齐 2.3 修改默认对齐数 3. 结构体传参 4.结构体实现位段 4.1 位段的内存分配 4.3 位段的…...
【JavaWeb】Jsp基本教程
目录 JSP概述作用一个简单的案例:使用JSP页面输出当前日期 JSP处理过程JSP 生命周期编译阶段初始化阶段执行阶段销毁阶段案例 JSP页面的元素JSP指令JSP中的page指令Include指令示例 taglib指令 JSP中的小脚本与表达式JSP中的声明JSP中的注释HTML的注释JSP注释 JSP行…...
外包干了25天,技术退步明显.......
先说一下自己的情况,大专生,18年通过校招进入杭州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...
C++(14): STL条件变量std::condition_variable
1. 简述 在C的标准模板库(STL)中,std::condition_variable是一个非常重要的同步原语,用于在多线程编程中实现线程间的条件同步。它允许一个或多个线程等待某个条件成立,当条件成立时,等待的线程会被唤醒并继…...
Harmony与Android项目结构对比
主要文件对应 Android文件HarmonyOS文件清单文件AndroidManifest.xmlmodule.json5Activity/Fragmententryability下的ts文件XML布局pages下的ets文件resresourcesModule下的build.gradleModule下的build-profile.json5gradlehvigor根目录下的build.gradle根目录下的build-profi…...
langchain 学习笔记-FunctionCalling三种方式
ChatGPT 基于海量的训练数据生成答案,所以它无法回答训练数据中没有的信息或搜索信息 。人们希望 ChatGPT 具有对话以外的各种功能,例如“我想管理我的待办事项列表”。 函数调用是对此类请求的响应。 通过使用函数调用,ChatGPT 现在可以在生…...
CNAS软件测试公司有什么好处?如何选择靠谱的软件测试公司?
CNAS认可是中国合格评定国家认可委员会的英文缩写,由国家认证认可监督管理委员会批准设立并授权的国家认可机构,统一负责对认证机构、实验室和检验机构等相关机构的认可工作。 在软件测试行业,CNAS认可具有重要意义。它标志着一个软件测试公…...
Cohere推出全新升级版RAG大型AI模型:支持中文,搭载1040亿参数,现开源其权重!
4月5日,知名类ChatGPT平台Cohere在其官方网站上发布了一款全新的模型——Command R。 据官方消息,Command R拥有1040亿个参数,并且支持包括英语、中文、法语、德语在内的10种语言。这一模型的显著特点之一在于其对内置的RAG(检索增…...
搭建前后端的链接(java)
搭建前后端的链接(java) 一.前提 1.1 javaEE 搭建前后端的链接首先需要用到javaEE,也就是java企业版,也就是java后端(后端javaSE) 利用javaEE和前端交互,javaSE和数据库交互,javaSE和javaEE之间再进行交互就实现了前后端的交互…...
Java多路查找树(含面试大厂题和源码)
多路查找树(Multiway Search Tree),也称为B树或B树,是一种自平衡的树形数据结构,用于存储大量数据,通常用于数据库和文件系统中。它允许在查找、插入和删除操作中保持数据的有序性,同时优化了磁…...
day6 | 哈希表 part-2 | 454 四数相加II 、383. 赎金信、15. 三数之和、18. 四数之和
今日任务 454 四数相加II (题目: . - 力扣(LeetCode))383 赎金信 (题目: . - 力扣(LeetCode)) 454 四数相加II 题目:. - 力扣(LeetCode) 给你四个整数数组 nums1、num…...
Redis常见数据类型(2)
目录 String字符串 常见命令 SET GET MGET MSET SETNX 计数命令 INCR INCRBY DECR DECRBY INCRFLOAT 其它命令 APPEND GETRANGE SETRANGE STRLEN String字符串 字符串是Redis最基础的数据类型, 关于字符串需要特别注意: (1)首先Redis中所有的键的类型都是字符…...
SparkBug解决:Type mismatch; found : org.apache.spark.sql.Column required: Double
def assginFlag(aizmuth:Double):Option[Int] {val interval 0.5val index (aizmuth / interval ).toIntif (index > 0 && index < 720 ) Some(index 1) else None} assginFlag方法中的条件判断条件 (index > 0 && index < 720) 返回的是一个布…...
从稀疏重构到精准定位:OMP-CS算法在DOA估计中的实战解析
1. 从稀疏信号到空间定位:OMP-CS算法的核心逻辑 第一次接触OMP-CS算法时,我盯着那堆数学公式发呆了半小时。直到把天线阵列想象成麦克风阵列,事情突然变得简单——这不就是通过多个麦克风判断声音方向的升级版吗?在雷达和通信系统…...
基于eNSP的园区网络高可用与安全隔离综合实验
1. 实验背景与核心价值 园区网络作为企业数字化转型的基础设施,其稳定性和安全性直接关系到日常运营效率。记得去年参与某金融机构网络改造项目时,他们的核心业务系统因为单点故障导致全网瘫痪4小时,直接损失超过百万。这个案例让我深刻认识到…...
Linux矢量设计挑战:Wine环境下的Adobe Illustrator CC安装与配置技术方案
Linux矢量设计挑战:Wine环境下的Adobe Illustrator CC安装与配置技术方案 【免费下载链接】illustratorCClinux Illustrator CC v17 installer for Gnu/Linux 项目地址: https://gitcode.com/gh_mirrors/il/illustratorCClinux 对于Linux用户而言,…...
当声带萎缩遇上AI建模:ElevenLabs老年女性语音不可忽视的5项生理声学特征补偿技术
更多请点击: https://intelliparadigm.com 第一章:声带萎缩与老年女性语音建模的交叉挑战 随着人口老龄化加剧,构建高保真、个体化老年女性语音合成模型面临独特的生理—声学耦合难题。声带萎缩导致基频降低、抖动率(jitter&…...
避坑指南:连接UR5实体机械臂与ROS MoveIt时,你最容易忽略的这3个配置细节
避坑指南:连接UR5实体机械臂与ROS MoveIt时,你最容易忽略的这3个配置细节 当仿真环境中的UR5机械臂完美运行MoveIt规划路径,却在切换到实体设备时遭遇连接失败,这种落差感往往源于几个隐蔽的配置陷阱。本文将从工业现场调试经验出…...
免费AI图像放大神器Upscayl:让模糊照片瞬间清晰的终极指南
免费AI图像放大神器Upscayl:让模糊照片瞬间清晰的终极指南 【免费下载链接】upscayl 🆙 Upscayl - #1 Free and Open Source AI Image Upscaler for Linux, MacOS and Windows. 项目地址: https://gitcode.com/GitHub_Trending/up/upscayl 你是否…...
实测Taotoken多模型路由的稳定性与延迟体感观察
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 实测Taotoken多模型路由的稳定性与延迟体感观察 本文基于一段时间的实际调用体验,分享对Taotoken平台稳定性和延迟的直…...
Mac用户必看:彻底解决NTFS读写难题的终极免费方案
Mac用户必看:彻底解决NTFS读写难题的终极免费方案 【免费下载链接】Free-NTFS-for-Mac Nigate: An open-source NTFS utility for Mac. It supports all Mac models (Intel and Apple Silicon), providing full read-write access, mounting, and management for NT…...
MacType终极指南:彻底解决Windows字体模糊问题的免费神器
MacType终极指南:彻底解决Windows字体模糊问题的免费神器 【免费下载链接】mactype Better font rendering for Windows. 项目地址: https://gitcode.com/gh_mirrors/ma/mactype 你是否厌倦了Windows系统上模糊不清的字体显示?长期面对锯齿边缘的…...
如何用LinkSwift解锁九大网盘下载新姿势?完整攻略揭秘
如何用LinkSwift解锁九大网盘下载新姿势?完整攻略揭秘 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼…...
