评论发布完整篇(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) 返回的是一个布…...

XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
Java入门学习详细版(一)
大家好,Java 学习是一个系统学习的过程,核心原则就是“理论 实践 坚持”,并且需循序渐进,不可过于着急,本篇文章推出的这份详细入门学习资料将带大家从零基础开始,逐步掌握 Java 的核心概念和编程技能。 …...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
[特殊字符] 手撸 Redis 互斥锁那些坑
📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...