评论发布完整篇(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

结果展示:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能前沿成科技竞争新高地

以下文章来源&#xff1a;经济参考报 近日&#xff0c;首届中国具身智能大会&#xff08;CEAI 2024&#xff09;在上海举行。作为人工智能领域的前沿热点&#xff0c;具身智能正逐步走进现实&#xff0c;成为当前全球科技竞争的新高地、未来产业的新赛道、经济发展的新引擎。 “…

厂房起火3D消防灭火安全救援模拟演练

深圳VR公司华锐视点依托前沿的VR虚拟现实制作、三维仿真和图形图像渲染技术&#xff0c;将参训者带入栩栩如生的火灾现场。佩戴VR头盔&#xff0c;参训者将真切体验火势蔓延的紧张与危机&#xff0c;身临其境地感受火灾的恐怖。 并且消防安全VR虚拟现实演练系统精心模拟了住宅、…

linux网络服务学习(6):多路径multipath解决iscsi多网卡识别错误问题

1.什么是多路径 1.1路径 物理层面一条数据的访问通道 访问方式&#xff1a; &#xff08;1&#xff09;以太网卡双绞网线以太网交换机 &#xff08;2&#xff09;HBA光纤卡光纤线光纤交换机 访问过程&#xff1a; &#xff08;1&#xff09;冗余链路failover&#xff1a…

Linux学习-网络TCP

TCP通信 TCP发端: socket connect send recv close TCP收端: socket bind listen accept send recv close 1.connect int connect(int sockfd, const struct sockaddr *addr, socklen_t …

德勤:《中国AI智算产业2024年四大趋势》

2023年《数字中国建设整体布局规划》的发布&#xff0c;明确了数字中国是构建数字时代竞争优势的关键支撑&#xff0c;是继移动互联网时代以来经济增长新引擎。当我们谈论数字中国的构建&#xff0c;不仅仅是在讨论一个国家级的技术升级&#xff0c;而是关乎如何利用数字技术来…

显示学习1(基于树莓派Pico) -- 基础

先上图为敬。 驱动的是0.96寸的OLED&#xff0c;SSD1315。使用的I2C接口驱动。 有一说一树莓派Pico用来学习底层真的太好了&#xff0c;没有之一。首先是价格便宜&#xff0c;10块钱包邮还要什么自行车。然后底层封装很完备&#xff0c;接近闭源。最后是用的python&#xff0c…

堆放砖块-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第47讲。 堆放砖块&#xf…

RuntimeError: Error(s) in loading state_dict for ZoeDepth解决方案

本文收录于《AI绘画从入门到精通》专栏,订阅后可阅读专栏内所有文章,专栏总目录:点这里。 大家好,我是水滴~~ 本文主要介绍在 Stable Diffusion WebUI 中使用 ControlNet 的 depth_zoe 预处理器时,出现的 RuntimeError: Error(s) in loading state_dict for ZoeDepth 异常…

TypeScript系列之-基本类型画图讲解

JS的类型(8)&#xff1a; null undefined string number boolean bigint symbol object&#xff08;含 Array, Function,Date.....&#xff09; TS的类型(87): 以上所有&#xff0c;加上 void, never, enum, unknown, any 再加上自定义类型 type interface 上一节我们说…

Google 发布 CodeGemma:7B 力压 CodeLLaMa-13B

刚刚发布&#xff01;Google 带来了新的 Gemma 家族成员&#xff0c;CodeGemma&#xff0c;这是基于预训练的 Gemma-2B 和 Gemma-7B 的代码生成模型。 其上下文窗口长度为8K&#xff0c;在另外 500 B 个主要由英语、数学和代码组成的 token 上进行了训练&#xff0c;改进了逻辑…

【企业场景】设计模式重点解析

设计模式 在平时的开发中&#xff0c;涉及到设计模式的有两块内容&#xff1a; 我们平时使用的框架&#xff08;比如spring、mybatis等&#xff09;我们自己开发业务使用的设计模式。 在平时的业务开发中&#xff0c;其实真正使用设计模式的场景并不多&#xff0c;虽然设计号…

allegro图片导入及调整的详细方法

目录 1. 图片转换2. 图片导入3. 导入图片调整3.1 图层调整 1. 图片转换 allegro只能导入IPF格式的文件&#xff1a; 正常情况下我们的图片都是JPG、BMP或者其他常见格式&#xff0c;需要将之转换为IPF格式才能导入&#xff0c;这里有工具。 需要工具在此 ->BMP转IPF工具 …

c++——sort()函数

一、代码和效果 #include<bits/stdc.h> using namespace std;int main() {int a[6]{1,45,2,5,456,7};sort(a,a6);for(int i0; i<6; i){cout<<a[i]<<" "<<endl;}return 0; } 二、sort函数解析 &#xff08;从小到大&#xff09; std::so…

[【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器

【JSON2WEB】01 WEB管理信息系统架构设计 【JSON2WEB】02 JSON2WEB初步UI设计 【JSON2WEB】03 go的模板包html/template的使用 【JSON2WEB】04 amis低代码前端框架介绍 【JSON2WEB】05 前端开发三件套 HTML CSS JavaScript 速成 【JSON2WEB】06 JSON2WEB前端框架搭建 【J…

长基线大高差RTK定位效果分析

为了评估基于GNSS参考站网的实时高精度滑坡监测算法效果&#xff0c;如图2所示&#xff0c;本文共收集了中国西北2019年年积日第271&#xff5e;277共7天的4个CORS站数据&#xff0c;分别为LZLC、BYBY、LXDX、LXJS&#xff0c; 2个黑方台滑坡监测站数据HF01和HF06&#xff0c;其…

快速掌握SpringBoot多环境开发

多环境开发 在一个项目当中可能同一套代码需要用于多种环境进行不同的用途例如&#xff1a;生产环境&#xff0c;开发环境&#xff0c;测试环境&#xff0c;需要通过配置进行不同环境的开发切换&#xff1a; spring:profiles:active: shengchan # 通过属性active进行选择 …

抖音评论ID提取工具|视频关键词评论批量采集软件

抖音评论ID提取工具&#xff1a;批量抓取抖音评论 抖音评论ID提取工具是一款功能强大的软件&#xff0c;可以帮助您批量抓取抖音视频下的评论信息。通过输入关键词和评论监控词&#xff0c;即可进行评论的抓取&#xff0c;并提供评论昵称、评论日期、评论内容、命中关键词以及所…

Matplotlib实现数据可视化

Matplotlib是Python中应用较为广泛的绘图工具之一&#xff0c;首次发布于2007年。它在函数设计上参考了MATLAB&#xff0c;因此名字以"Mat"开头&#xff0c;中间的"plot"代表绘图功能&#xff0c;结尾的"lib"表示它是一个集合。Matplotlib支持众…

MQ之————如何保证消息的可靠性

MQ之保证消息的可靠性 1.消费端消息可靠性保证&#xff1a; 1.1 消息确认&#xff08;Acknowledgements&#xff09;&#xff1a; 消费者在接收到消息后&#xff0c;默认情况下RabbitMQ会自动确认消息&#xff08;autoAcktrue&#xff09;。为保证消息可靠性&#xff0c;可以…

CST电磁仿真基本单位设置和保存结果【仿真教程】

保存结果的Result Navigator 积累的结果一目了然&#xff01; 用户界面上的Result Navigator 在一个仿真工程中更改变量取值进行仿真分析或者改变设置进行仿真分析时&#xff0c;之前的1DResult会不会消失呢&#xff1f; 1D Result&#xff1a;CST中1D Result指的是Y值取决…