"小和山的菜鸟们",为前端开发者提供技术相关资讯以及系列基础文章。为更好的用户体验,请您移至我们官网小和山的菜鸟们 ( https://xhs-rookies.com/ ) 进行学习,及时获取最新文章。
"Code tailor" ,如果您对我们文章感兴趣、或是想提一些建议,微信关注 “小和山的菜鸟们” 公众号,与我们取的联系,您也可以在微信上观看我们的文章。每一个建议或是赞同都是对我们极大的鼓励!
我们这次学了一些新内容,我们需要将之前的改版。
如果我们需要对某个评论进行点赞怎么办呢?
如果按照上次那样子通过某个属性传入控制是否显示点赞,这是可以的。
我们上次抽象了 InputCompoent
输入框组件和 EvaluateCompoent
列表展示组件这两个组件,这次我们需要新增一个 comment
组件来完成点赞功能。
不需要的组件去除
上次我们将 InputCompoent
输入框组件和 EvaluateCompoent
列表展示组件抽象出来放置于 component
文件夹中,我们先将这两个组件直接放置于App.js
中。(为了直观,我们先这两个已经抽象好的给直接放置于 App.js
中)
我们只需要抽象一个comment
组件,给上次的EvaluateCompoent
列表展示组件加上我们的点赞功能,每个列表中的评论我们都可以进行点赞。
因此我们将首页App.js
修改为如下:
import React, { PureComponent } from 'react'
import Comment from './comment'
import './App.css'
class App extends PureComponent {
constructor() {
super()
this.state = {
title: 'Hello React',
desc: '你知道有这么一个团队吗?他们怀揣梦想,艰苦奋斗,作为一群大学生菜鸟,放弃了平时娱乐的时间,选择一起学习,一起成长,将平时学习的笔记,心得总结为文章,目的很简单,希望可以帮助向他们一样的菜鸟们?你想了解更多吗?快搜索微信公众号:小和山的菜鸟们,加入他们吧!',
comments: [
{
headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
time: new Date(2021, 4, 14, 21, 2, 30),
nickName: '小菜鸟',
detail: '这是一个即将推出系列文章的团队,我们一起期待他们的作品吧!',
liked: true,
likeNum: 23,
},
],
text: '',
}
}
render() {
const { title, desc, comments, text } = this.state
return (
<div className="App">
<h2>{title}</h2>
<div className="desc">{desc}</div>
<div style={{ width: '100%' }}>
<p className="commentsTitle">评论</p>
{comments.map((item, index) => {
return (
<Comment
key={item.time.getTime()}
changeLike={() => {
this.changeLike(index)
}}
{...item}
/>
)
})}
</div>
<div className="newComment">
<div style={{ display: 'flex' }}>
<img src="https://xhs-rookies.com/img/rookie-icon.png" className="" alt="" />
<textarea value={text} onChange={(e) => this.changeText(e)} placeholder="请输入评论" />
</div>
<div
className="submit"
onClick={() => {
this.addComment()
}}
>
发表
</div>
</div>
</div>
)
}
changeText(e) {
this.setState({ text: e.target.value })
}
changeLike(index) {
let newArray = [...this.state.comments]
let newItem = { ...newArray[index] }
if (newItem.liked) {
newItem.liked = false
newItem.likeNum -= 1
} else {
newItem.liked = true
newItem.likeNum += 1
}
newArray[index] = newItem
this.setState({
comments: newArray,
})
}
addComment() {
if (!this.state.text) {
alert('请输入留言内容')
return
}
let detail = this.state.text
this.setState({ text: '' })
let newComment = {
headPortrait: 'https://xhs-rookies.com/img/rookie-icon.png',
time: new Date(),
nickName: '小菜鸟',
detail,
liked: false,
likeNum: 0,
}
this.setState({
comments: [newComment, ...this.state.comments],
})
}
}
App.propTypes = {}
export default App
首先我们需要考虑这个组件需要什么功能。
除了上次抽象出来的:
需要有头像、时间、名字、内容这几个外,我们还需要一个点赞按钮,这个按钮点击一下变成红色,并且数字加一,再次点击颜色重新改为灰色,并且数字减一。
<span className={'likeBox ' + (liked ? 'like' : 'unlike')} onClick={() => changeLike()}>
<span className="icon"> </span>
<span>{!!likeNum && likeNum}</span>
</span>
一个 span
用于存放点赞图标,一个用于显示点赞的数字。
这次我们数据变得更加多了,外面传给该组件的数据越来越多之后,我们如何判断,或是说保证给进来内容是正确的呢?(是否为空?)
我们采用propType
进行内容检测,如果出现错误,可以快速帮我们定位错误并进行修改。
Comment.propTypes = {
nickName: PropTypes.string.isRequired,
time: PropTypes.object.isRequired,
headPortrait: PropTypes.string.isRequired,
detail: PropTypes.string.isRequired,
liked: PropTypes.bool.isRequired,
likeNum: PropTypes.number.isRequired,
changeLike: PropTypes.func.isRequired,
}
那我们将之前的EvaluateCompoent
列表展示组件加上点赞功能,在将数据检测功能添加进去,我们的 comment
组件就完成了。
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import './comment.css'
class Comment extends PureComponent {
render() {
const { nickName, time, headPortrait, detail, liked, likeNum, changeLike } = this.props
return (
<div className="comment">
<div className="info">
<img src={headPortrait} alt="头像" />
<div>
<p className="nickname">{nickName}</p>
<p className="time">{this.getTime(time)}</p>
</div>
</div>
<div className="detail" style={{ marginBottom: '10px' }}>
{detail}
</div>
<div className="toolBox">
<span className={'likeBox ' + (liked ? 'like' : 'unlike')} onClick={() => changeLike()}>
<span className="icon"> </span>
<span>{!!likeNum && likeNum}</span>
</span>
<span className="share icon"> </span>
</div>
</div>
)
}
getTime(time) {
const year = time.getFullYear()
const month = time.getMonth() + 1
const day = time.getDate()
const hour = String(time.getHours()).padStart(2, '0')
const minute = String(time.getMinutes()).padStart(2, '0')
const second = String(time.getSeconds()).padStart(2, '0')
return `${year}.${month}.${day} ${hour}:${minute}:${second}`
}
}
Comment.propTypes = {
nickName: PropTypes.string.isRequired,
time: PropTypes.object.isRequired,
headPortrait: PropTypes.string.isRequired,
detail: PropTypes.string.isRequired,
liked: PropTypes.bool.isRequired,
likeNum: PropTypes.number.isRequired,
changeLike: PropTypes.func.isRequired,
}
export default Comment
我们建议采用 codesanbox
的形式可以在线快速访问当前实战案例。
下节中我们将讲述使用React中State的相关信息,深入理解 setState 方法以及一些相关内容。敬请期待!
在今天的网页中 javascript 使用相当广泛,它能使网页增加互动性。javascript 使...
最近制作下拉菜单时,打算用纯CSS,忽又看到令人头痛的CSS hack代码(平时很少关...
本期简介 一款原计划进入欧美市场的产品,意外在东南亚地区收获令人惊喜的数据反...
.club域名 一年多少钱?如果从定价来看的话,普通的. club域名 注册一年原价是69...
一、设置列表的符号 list-style-type: 属性;//设置列表样式 list-style-type: n...
今天为大家分享Dreamweaver浏览器测试方法,教程很不错,很值得大家学习,推荐到...
简介: 作为云原生架构基础设施的核心组成部分,容器安全一直是企业关注的核心问...
送大家以下java学习资料,文末有领取方式 一、为什么要用分布式ID? 在说分布式I...
不带边框的iframe因为能和网页无缝的结合从而不刷新页面的情况下更新页面的部分...
一,盒子塌陷是什么? 本应该在父盒子内部的元素跑到了外部。 二,为什么会出现...