当前位置: 首页 > news >正文

评论发布完整篇(react版)

        此篇文章阐述评论的最新、最热之间的tab标签切换(包括当前所在tab标签的高亮显示问题);当前评论的删除;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序,点赞数量越多,此条评论越靠前;最新tab标签页所展示的内容是根据当前评论发布时间来进行排序,随着时间的推移,此条评论越靠前。

话不多说,上代码:

1.安装必要插件

classnamesdayjslodashnode-sasssass-loaderuuidlodash

安装命令如下:

classnames:npm install classnames或者 yarn add classnames

dayjs:npm install dayjs 或者 yarn add dayjs

lodash:npm install lodash 或者 yarn add lodash

安装scss相关包:npm install sassnpm 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标签切换&#xff08;包括当前所在tab标签的高亮显示问题&#xff09;&#xff1b;当前评论的删除&#xff1b;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序&#xff0c;点赞数量…...

前端window.open的简单使用

JavaScript 中的 Window.open() 用法详解-CSDN博客 window.open("https://www.baidu.com/?tn49055317_12_hao_pg", _blank);...

基于开源软件构建存储解决方案的思考

近来看了一些IBM的存储产品的资料&#xff0c;有一些收获。 依据存储软件和搭配硬件&#xff0c;IBM存储产品的组合&#xff0c;大致分类如下&#xff1a; 自研存储软件&#xff0c;搭配自研专有硬件自研存储软件&#xff0c;搭配通用服务器硬件&#xff0c;比如IBM Storage S…...

【leetcode】动态规划::前缀和(二)

标题&#xff1a;【leetcode】前缀和&#xff08;二&#xff09; 水墨不写bug 正文开始&#xff1a; &#xff08;一&#xff09; 和为K的子数组 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续…...

SpringBoot自动装配原理之@Import注解解析

文章目录 1. 概述2. 使用2.1 导入普通Bean2.2 导入配置类2.3 导入 ImportSelector 实现类2.4 导入 ImportBeanDefinitionRegistrar 实现类 3. 区别 1. 概述 当谈及现代Java开发领域中的框架选择时&#xff0c;SpringBoot无疑是无与伦比的热门之选。其简化了开发流程&#xff0…...

49 样式迁移【李沐动手学深度学习v2课程笔记】

1. 样式迁移&#xff08;Style Transfer) 计算机视觉的应用之一&#xff0c;将样式图片中的样式&#xff08;比如油画风格等&#xff09;迁移到内容图片&#xff08;比如实拍的图片&#xff09;上&#xff0c;得到合成图片 可以理解成为一个滤镜&#xff0c;但相对于滤镜来讲…...

Linux的学习之路:4、权限

一、Linux权限的概念 权限我们都熟悉&#xff0c;最常见的就是在看电视时需要vip这个就是权限&#xff0c;然后在Linux就是有两个权限&#xff0c;就是管理员也就是超级用户和普通的用户 命令&#xff1a;su [用户名] 功能&#xff1a;切换用户。 例如&#xff0c;要从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概述作用一个简单的案例&#xff1a;使用JSP页面输出当前日期 JSP处理过程JSP 生命周期编译阶段初始化阶段执行阶段销毁阶段案例 JSP页面的元素JSP指令JSP中的page指令Include指令示例 taglib指令 JSP中的小脚本与表达式JSP中的声明JSP中的注释HTML的注释JSP注释 JSP行…...

外包干了25天,技术退步明显.......

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入杭州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...

C++(14): STL条件变量std::condition_variable

1. 简述 在C的标准模板库&#xff08;STL&#xff09;中&#xff0c;std::condition_variable是一个非常重要的同步原语&#xff0c;用于在多线程编程中实现线程间的条件同步。它允许一个或多个线程等待某个条件成立&#xff0c;当条件成立时&#xff0c;等待的线程会被唤醒并继…...

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 基于海量的训练数据生成答案&#xff0c;所以它无法回答训练数据中没有的信息或搜索信息 。人们希望 ChatGPT 具有对话以外的各种功能&#xff0c;例如“我想管理我的待办事项列表”。 函数调用是对此类请求的响应。 通过使用函数调用&#xff0c;ChatGPT 现在可以在生…...

CNAS软件测试公司有什么好处?如何选择靠谱的软件测试公司?

CNAS认可是中国合格评定国家认可委员会的英文缩写&#xff0c;由国家认证认可监督管理委员会批准设立并授权的国家认可机构&#xff0c;统一负责对认证机构、实验室和检验机构等相关机构的认可工作。 在软件测试行业&#xff0c;CNAS认可具有重要意义。它标志着一个软件测试公…...

Cohere推出全新升级版RAG大型AI模型:支持中文,搭载1040亿参数,现开源其权重!

4月5日&#xff0c;知名类ChatGPT平台Cohere在其官方网站上发布了一款全新的模型——Command R。 据官方消息&#xff0c;Command R拥有1040亿个参数&#xff0c;并且支持包括英语、中文、法语、德语在内的10种语言。这一模型的显著特点之一在于其对内置的RAG&#xff08;检索增…...

搭建前后端的链接(java)

搭建前后端的链接(java) 一.前提 1.1 javaEE 搭建前后端的链接首先需要用到javaEE&#xff0c;也就是java企业版&#xff0c;也就是java后端(后端javaSE) 利用javaEE和前端交互&#xff0c;javaSE和数据库交互&#xff0c;javaSE和javaEE之间再进行交互就实现了前后端的交互…...

Java多路查找树(含面试大厂题和源码)

多路查找树&#xff08;Multiway Search Tree&#xff09;&#xff0c;也称为B树或B树&#xff0c;是一种自平衡的树形数据结构&#xff0c;用于存储大量数据&#xff0c;通常用于数据库和文件系统中。它允许在查找、插入和删除操作中保持数据的有序性&#xff0c;同时优化了磁…...

day6 | 哈希表 part-2 | 454 四数相加II 、383. 赎金信、15. 三数之和、18. 四数之和

今日任务 454 四数相加II (题目: . - 力扣&#xff08;LeetCode&#xff09;)383 赎金信 &#xff08;题目: . - 力扣&#xff08;LeetCode&#xff09;&#xff09; 454 四数相加II 题目&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给你四个整数数组 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) 返回的是一个布…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...