前言
最近想用react 写一款自己的博客 此篇文章主要为设计一个评论框组件~
最终的功能实现效果图
需求
1、用户对某一文章评论 系统可以获取用户的信息 并展示出来
2、其余用户可以评论别人的回复信息
3、输入QQ 可以后台查询对应的用户头像保存下来
数据库设计
用户表
id | 用户名 | 联系方式 | 头像地址 |
---|---|---|---|
评论表
评论id | 文章id | 评论内容 | 用户id | 状态 | 点赞数 | 回复信息 |
---|---|---|---|---|---|---|
状态分为 是否审核通过 防止恶意评论
回复表
评论id | 文章id | 回复的内容 | 用户id | 被回复人id | 状态 | 点赞数 | 回复信息 |
---|---|---|---|---|---|---|---|
前端评论框组件设计
前端主要使用antd 里面的form 表单 以及留言板 模块
主要的逻辑
- 用户在输入qq号那一栏 会利用正则判断是否为qq号 如果为qq号 则动态设置用户联系方式那一栏为qq邮箱地址,并且保存用户的qq号 利用后端去查询用户的头像。
- 首次进入 会判断 localstorage里面有没有用户信息 如果没有则让用户填写用户信息
- 前端利用nanoid生成随机数 确保用户id的唯一性
- 当用户在输入留言以后 会将用户的信息 用localstorage 保存到本地 这样 用户下次登录 或者再次评论别人的信息 就不用再次填写信息,(打算以后改为用户利用qq登录功能)
- 若为文章评论 还要隐去评论表的取消按钮 若为评论他人信息 要保留评论的取消按钮
- 还要判断出该条回复信息 是否为评论他人的信息
import React,{useState,useEffect} from 'react'
import { Form, Input, Button,message} from 'antd';
import moment from 'moment';
import {nanoid} from 'nanoid'; //生成随机数 用确保用户的id唯一
import axios from 'axios'
import servicePath from '../config/apiUrl'
const { TextArea } = Input;
function MessageModal(props){
const [form] = Form.useForm();
const [flag,setFlag] = useState(false)
const [cancelFlag,setCancelFlag] = useState(false)
const [replyId,setReplyId] = useState(props.replyId)
const [loadings,setLoadings] = useState(false)
const [imgUrl,setImgUrl] =useState("")
useEffect(()=>{
// 如果有用户id 就设置用户名跟联系方式 且 不能修改
if(localStorage.getItem("user_id")){
setFlag(true)
form.setFieldsValue({
name:localStorage.getItem("userName")?localStorage.getItem("userName"):"",
contact:localStorage.getItem("contact")?localStorage.getItem("contact"):""
})
if(localStorage.getItem("img_url")){
setImgUrl(localStorage.getItem("img_url"))
}
}
if(!props.closeComment){
// 如果不是点击回复进来的 是没有 closeComment函数 即 点击取消的 事件
setCancelFlag(true)
}
},[])
const onFinish = (values: any) => {
setLoadings(true)
// 用户提交评论信息以后把用户名 用户联系方式 用户的id 保存到本地上
let commentData={
user_id:localStorage.getItem("user_id") ? localStorage.getItem("user_id") : nanoid(),
createtime:moment().format('X'),
state:0,
likes:0,
replys:null,
article_id:props.id,
content:values.content,
contact:values.contact,
name:values.name,
img_url:imgUrl,
// 以下为回复评论的数据
comment_id:replyId && replyId.comment_id,
reply_id:replyId && replyId.user_id,
}
axios({
method:'post',
url:servicePath.addComment,
data:commentData,
withCredentials: true
}).then(
res=>{
setLoadings(false)
if(res.data.isScuccess){
form.setFieldsValue({
content:""
})
localStorage.setItem("userName",commentData.name)
localStorage.setItem("contact",commentData.contact)
localStorage.setItem("user_id",commentData.user_id)
localStorage.setItem("img_url",imgUrl)
setFlag(true)
message.success('评论成功,请等待审核~')
!cancelFlag && props.closeComment()
}else{
message.error('评论失败,请刷新重试~');
}
}
)
};
const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};
// 根据输入的qq号或昵称设置 邮箱 12位邮箱
const changeContact =()=>{
let reg = /^[1-9][0-9]{4,9}$/gim
if(reg.test(form.getFieldValue("name"))){
form.setFieldsValue({
contact:form.getFieldValue("name")+'@qq.com'
})
//获取QQ头像 没有找到合适的接口获取QQ昵称
setImgUrl('https://q2.qlogo.cn/headimg_dl?dst_uin='+form.getFieldValue("name")+'&spec=100')
}else{
setImgUrl("https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png")
form.setFieldsValue({
contact:""
})
}
}
return(
<Form
name="basic"
labelCol={{ span: 0 }}
wrapperCol={{ span: 24 }}
initialValues={{ remember: true }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
className = "message-modal"
form={form}
>
<Form.Item
label=""
name="name"
rules={[{ required: true, message: '请确认昵称/QQ号' }]}
className ={flag ? "display-none" : "">
<Input placeholder="昵称/QQ号" onChange={changeContact}/>
</Form.Item>
<Form.Item
label=""
name="contact"
rules={[
{ required: true, message: '请确认您的邮箱' },
{
pattern: /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/,
message: '邮箱格式不正确',
},
]}
className ={flag ? "display-none" : ""}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
<Form.Item
label=""
name="content"
rules={[{ required: true, message: '输入您的留言 ' }]}
>
<TextArea showCount maxLength={100} placeholder="1.输入您的留言 2.在昵称框输入QQ号可自动识别头像哦" />
</Form.Item>
<Form.Item wrapperCol={{ offset: 0, span: 24 }}>
<Button htmlType="button" className ={cancelFlag ? "display-none" : "margin-r10"} onClick={props.closeComment}>
取消
</Button>
<Button type="primary" htmlType="submit" loading={loadings}>
提交评论 ✪ω✪
</Button>
</Form.Item>
</Form>)
}
版权声明:本文为weixin_42609477原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。