在学习了 react 的 JSX 语法以及 类组件 后,现在我们来实现一个 评论列表案例
对应该案例主要有以下几个功能点:
- 列表展示功能
- 发表评论功能
- 清空评论功能
- 删除评论功能
对于该案例的静态结构以及样式这里就不去过多的进行说明了,我们直接给出它的静态结构和样式
src/index.css
.app {
width: 300px;
padding: 10px;
border: 1px solid #999;
}
.user {
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.content {
width: 100%;
box-sizing: border-box;
margin-bottom: 10px;
}
.no-comment {
text-align: center;
margin-top: 30px;
}
src/index.js
/**
* 1. 导入react和react-dom
* 2. 创建 react 元素
* 3. 把 react 元素渲染到页面
*/
import React from 'react';
import ReactDom from 'react-dom/client';
import { Component } from 'react';
import './index.css'
/*
主要实现的功能:
1. 展示评论功能
2. 清空评论功能
3. 发表评论功能
4. 删除评论功能
5. 没有更多评论的处理
*/
class App extends Component {
render() {
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" />
<br />
<textarea
className="content"
cols="30"
rows="10"
placeholder="请输入评论内容"
/>
<br />
<button>发表评论</button>
<button>清空评论</button>
</div>
<ul>
<li>
<h3>评论人:刘德华</h3>
<p>评论内容:冰雨</p>
<button>删除</button>
</li>
</ul>
<div className="no-comment">暂无评论</div>
</div>
)
}
}
// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
<React.Fragment>
<App></App>
</React.Fragment>
);
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);
先来看一下样式吧
列表展示功能:
渲染评论列表(列表渲染)
-
在state中初始化评论列表数据
-
使用数组的map方法遍历列表数据
-
给每个li添加key属性
/**
* 1. 导入react和react-dom
* 2. 创建 react 元素
* 3. 把 react 元素渲染到页面
*/
import React from 'react';
import ReactDom from 'react-dom/client';
import { Component } from 'react';
import './index.css'
/*
主要实现的功能:
1. 展示评论功能
1.1 通过 state 提供评论列表数据
1.2 通过 map 动态渲染
2. 清空评论功能
3. 发表评论功能
4. 删除评论功能
5. 没有更多评论的处理
*/
class App extends Component {
state = ({
list: [
{
id: 1,
name: '张三',
content: '宝,我昨天去输液了。你知道是输的什么液吗?是想你的夜'
},
{
id: 2,
name: '李四',
content: '哈哈,笑死!!!居然还有这种土味情话'
},
{
id: 3,
name: '王五',
content: '我要定一个小目标,那就是先挣它一个亿!'
},
{
id: 4,
name: '赵六',
content: '嚯哟,您这小目标可真是够小的,祝早日实现!!!'
}
]
})
render() {
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" />
<br />
<textarea
className="content"
cols="30"
rows="10"
placeholder="请输入评论内容"
/>
<br />
<button>发表评论</button>
<button>清空评论</button>
</div>
<ul>
{
this.state.list.map(item =>
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
<button>删除</button>
</li>
)
}
</ul>
<div className="no-comment">暂无评论</div>
</div>
)
}
}
// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
<React.Fragment>
<App></App>
</React.Fragment>
);
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);
清空评论功能:
-
给清空评论按钮注册事件
-
清空评论列表
-
没有更多评论的处理
/**
* 1. 导入react和react-dom
* 2. 创建 react 元素
* 3. 把 react 元素渲染到页面
*/
import React from 'react';
import ReactDom from 'react-dom/client';
import { Component } from 'react';
import './index.css'
/*
主要实现的功能:
1. 展示评论功能
1.1 通过 state 提供评论列表数据
1.2 通过 map 动态渲染
2. 清空评论功能
3. 发表评论功能
4. 删除评论功能
5. 没有更多评论的处理
*/
class App extends Component {
state = ({
list: [
{
id: 1,
name: '张三',
content: '宝,我昨天去输液了。你知道是输的什么液吗?是想你的夜'
},
{
id: 2,
name: '李四',
content: '哈哈,笑死!!!居然还有这种土味情话'
},
{
id: 3,
name: '王五',
content: '我要定一个小目标,那就是先挣它一个亿!'
},
{
id: 4,
name: '赵六',
content: '嚯哟,您这小目标可真是够小的,祝早日实现!!!'
}
]
})
render() {
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" />
<br />
<textarea
className="content"
cols="30"
rows="10"
placeholder="请输入评论内容"
/>
<br />
<button>发表评论</button>
<button onClick={this.clearAll}>清空评论</button>
</div>
{
// this.state.list.length === 0 ? (<div className="no-comment">暂无评论</div>) :
// (
// <ul>
// {
// this.state.list.map(item =>
// <li key={item.id}>
// <h3>评论人:{item.name}</h3>
// <p>评论内容:{item.content}</p>
// <button>删除</button>
// </li>
// )
// }
// </ul>
// )
// 或者下面这种做法
}
{
this.renderList()
}
</div>
)
}
// 清空评论
clearAll = () => {
this.setState({
list: []
})
}
// 没有更多评论的处理
renderList() {
if(this.state.list.length === 0) {
return (<div className="no-comment">暂无评论</div>);
} else {
return (
<ul>
{
this.state.list.map(item =>
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
<button>删除</button>
</li>
)
}
</ul>
)
}
}
}
// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
<React.Fragment>
<App></App>
</React.Fragment>
);
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);
删除评论功能:
/**
* 1. 导入react和react-dom
* 2. 创建 react 元素
* 3. 把 react 元素渲染到页面
*/
import React from 'react';
import ReactDom from 'react-dom/client';
import { Component } from 'react';
import './index.css'
/*
主要实现的功能:
1. 展示评论功能
1.1 通过 state 提供评论列表数据
1.2 通过 map 动态渲染
2. 清空评论功能
3. 发表评论功能
4. 删除评论功能
5. 没有更多评论的处理
*/
class App extends Component {
state = ({
list: [
{
id: 1,
name: '张三',
content: '宝,我昨天去输液了。你知道是输的什么液吗?是想你的夜'
},
{
id: 2,
name: '李四',
content: '哈哈,笑死!!!居然还有这种土味情话'
},
{
id: 3,
name: '王五',
content: '我要定一个小目标,那就是先挣它一个亿!'
},
{
id: 4,
name: '赵六',
content: '嚯哟,您这小目标可真是够小的,祝早日实现!!!'
}
]
})
render() {
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" />
<br />
<textarea
className="content"
cols="30"
rows="10"
placeholder="请输入评论内容"
/>
<br />
<button>发表评论</button>
<button onClick={this.clearAll}>清空评论</button>
</div>
{
this.renderList()
}
</div>
)
}
// 清空评论
clearAll = () => {
this.setState({
list: []
})
}
// 没有更多评论的处理
renderList() {
if(this.state.list.length === 0) {
return (<div className="no-comment">暂无评论</div>);
} else {
return (
<ul>
{
this.state.list.map(item =>
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
{
// 传参写法:
// 写法1:<button onClick={() => this.del(item.id)}>删除</button>
// 写法2:<button onClick={this.del.bind(this, item.id)}>删除</button>
}
<button onClick={this.del.bind(this, item.id)}>删除</button>
</li>
)
}
</ul>
)
}
}
// 删除评论功能
del = (id) => {
// console.log(id);
this.setState({
list: this.state.list.filter(item => item.id !== id)
})
}
}
// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
<React.Fragment>
<App></App>
</React.Fragment>
);
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);
发表评论功能 :
获取评论信息,评论人和评论内容(受控组件)
-
使用受控组件的方式获取评论数据
发表评论,更新评论列表(更新状态)
-
给comments增加一条数据
边界处理
-
清空内容
-
判断非空
/**
* 1. 导入react和react-dom
* 2. 创建 react 元素
* 3. 把 react 元素渲染到页面
*/
import React from 'react';
import ReactDom from 'react-dom/client';
import { Component } from 'react';
import './index.css'
/*
主要实现的功能:
1. 展示评论功能
1.1 通过 state 提供评论列表数据
1.2 通过 map 动态渲染
2. 清空评论功能
3. 发表评论功能
4. 删除评论功能
5. 没有更多评论的处理
*/
class App extends Component {
state = ({
list: [
{
id: 1,
name: '张三',
content: '宝,我昨天去输液了。你知道是输的什么液吗?是想你的夜'
},
{
id: 2,
name: '李四',
content: '哈哈,笑死!!!居然还有这种土味情话'
},
{
id: 3,
name: '王五',
content: '我要定一个小目标,那就是先挣它一个亿!'
},
{
id: 4,
name: '赵六',
content: '嚯哟,您这小目标可真是够小的,祝早日实现!!!'
}
],
name: '',
content: ''
})
render() {
return (
<div className="app">
<div>
<input className="user" type="text" placeholder="请输入评论人" value={this.state.name} onChange={this.handleChange} name="name" />
<br />
<textarea
className="content"
cols="30"
rows="10"
placeholder="请输入评论内容"
value={this.state.content}
onChange={this.handleChange}
name="content"
/>
<br />
<button onClick={this.add}>发表评论</button>
<button onClick={this.clearAll}>清空评论</button>
</div>
{
this.renderList()
}
</div>
)
}
// 清空评论
clearAll = () => {
this.setState({
list: []
})
}
// 没有更多评论的处理
renderList() {
if(this.state.list.length === 0) {
return (<div className="no-comment">暂无评论</div>);
} else {
return (
<ul>
{
this.state.list.map(item =>
<li key={item.id}>
<h3>评论人:{item.name}</h3>
<p>评论内容:{item.content}</p>
<button onClick={this.del.bind(this, item.id)}>删除</button>
</li>
)
}
</ul>
)
}
}
// 删除评论功能
del = (id) => {
// console.log(id);
this.setState({
list: this.state.list.filter(item => item.id !== id)
})
}
// 发表评论功能
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
})
}
add = () => {
const { name, content, list } = this.state;
// 当 name 或者 content 没有值
if(!name || !content){
return alert('信息不完整!');
}
// 添加评论
this.setState({
list: [{id: Date.now(), name: name, content: content} ,...list],
name: '',
content: ''
})
}
}
// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (
<React.Fragment>
<App></App>
</React.Fragment>
);
// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);