TODOList
这里没有对组件进行封装,而是全部写到了一个页面中 如果要对组件进行拆分的话,需要拆分为三个组件,分别是:
- 头部搜索框
- 列表
- 底部全选框
下面是比较标准的React开发规范
todolist
├─ package.json
├─ public
│ ├─ favicon.ico
│ └─ index.html
├─ src
│ ├─ App.css
│ ├─ App.jsx
│ ├─ Components
│ │ ├─ Footer
│ │ │ ├─ index.css
│ │ │ └─ index.jsx
│ │ ├─ Header
│ │ │ ├─ index.css
│ │ │ └─ index.jsx
│ │ ├─ item
│ │ │ ├─ index.css
│ │ │ └─ index.jsx
│ │ └─ List
│ │ ├─ index.css
│ │ └─ index.jsx
│ └─ index.js
└─ yarn.lock
需求分析
- 输入框中输入数据后,按下回车,可以将待办事项添加到列表中
- 点击未完成的待办事项,可以将其标注为已完成。如果全部已完成,那么修改全选部分的状态
- 鼠标悬浮到每一项后面的时候,出现删除按钮,点击删除按钮可以将元素删除
- 全选部分可以控制待办列表的状态:全部已完成或全部未完成
代码实现
这里为了方便,直接引入了
ant-design
组件库
添加待办
给Input框绑定value
以及onChange
事件
<div>
<Input
value={this.state.text}
onChange={(e) => this.setState({ text: e.target.value })}
placeholder='请输入...'
onKeyDown={this.handleEnterKeyDown}
/>
</div>
按下回车要能触发事件,因此我们需要给输入框绑定onKeyDown
事件,并判断按下的键是否是enter
不难发现,每一次新添加的内容需要添加到列表的首位,但其实利用ES6的解构运算,很容易实现,如下代码所示:
handleEnterKeyDown = (e) => {
// 监听回车事件
if (e.keyCode === 13) {
const { text, list } = this.state;
if (text.trim() === '') {
message.error('请输入内容');
} else {
const { list } = this.state;
let item = {
id: list.length + 1,
isFinished: false,
text,
};
const newList = [item, ...list];
let [sum, flag] = [0, false];
newList.forEach((e) => (e.isFinished ? (sum += 1) : (sum += 0)));
flag = sum === newList.length;
this.setState({
list: newList,
text: '',
isFinishedAll: flag,
});
message.success('添加成功');
}
}
};
这里的小细节是,当输入之前,所有的待办处于已完成的状态,那么我们新添加一个待办之后,势必要将全选框的状态进行修改(因为此时已经不是全部都完成了)
完成待办
我们这里使用到了ant-design
的列表组件,所以我们可以直接给List.Item
绑定点击事件,从而进行逻辑的处理
有一个小细节,就是当所有的待办都被完成之后,要修改下面全选框的状态
删除待办
我们的需求是:鼠标悬浮在某一项上时,该项后面出现删除按钮。并且同一时间下有且仅有一项后面可以出现这个按钮。
因此我们需要监听鼠标的移入和移出事件,并且设定状态来判断鼠标悬浮于第几个待办上
全选/全不选
完整代码
import { Button, Checkbox, Divider, Input, List, message, Typography } from 'antd';
import React, { Component } from 'react';
export default class TodoList extends Component {
state = {
list: [
{
id: 1,
isFinished: false,
text: '吃饭',
},
],
isFinishedAll: false,
mouse: {
in: false,
index: -1,
},
text: '',
};
handleEnterKeyDown = (e) => {
// 监听回车事件
if (e.keyCode === 13) {
const { text, list } = this.state;
if (text.trim() === '') {
message.error('请输入内容');
} else {
const { list } = this.state;
let item = {
id: list.length + 1,
isFinished: false,
text,
};
const newList = [item, ...list];
let [sum, flag] = [0, false];
newList.forEach((e) => (e.isFinished ? (sum += 1) : (sum += 0)));
flag = sum === newList.length;
this.setState({
list: newList,
text: '',
isFinishedAll: flag,
});
message.success('添加成功');
}
}
};
handleFinish = (item) => {
console.log(item);
let { list } = this.state;
if (!item.isFinished) {
// 找出list中与item的id相同的元素
let index = list.findIndex((e) => e.id === item.id);
console.log('index', index);
list[index].isFinished = true;
this.setState({
list,
});
message.success('恭喜您,任务完成!');
}
let sum = 0;
list.forEach((e) => (e.isFinished ? sum++ : null));
if (sum === list.length) {
this.setState({
isFinishedAll: true,
});
}
};
handleMouseOver = (flag, item) => {
this.setState({
mouse: {
in: flag,
index: item.id,
},
});
};
handleCheckBoxChecked = (e) => {
const { checked } = e.target;
let { list } = this.state;
list.forEach((e) => (e.isFinished = checked));
this.setState({
list,
isFinishedAll: checked,
});
const msg = checked ? '完成' : '取消';
message.success(`已${msg}全部任务`);
};
handleDelete = (e, item) => {
console.log('delete');
e.stopPropagation();
let { list } = this.state;
this.setState({
list: list.filter((e) => e.id !== item.id),
});
message.success(`已删除${item.text}`);
};
render() {
return (
<div>
<h2>待办事项</h2>
<div>
<Input
value={this.state.text}
onChange={(e) => this.setState({ text: e.target.value })}
placeholder='请输入...'
onKeyDown={this.handleEnterKeyDown}
/>
</div>
<>
<Divider orientation='left'>列表</Divider>
<List
footer={
<div>
<span>
<Checkbox
onChange={this.handleCheckBoxChecked}
checked={this.state.isFinishedAll}
/>
</span>
<span>已完成{this.state.list.filter((e) => e.isFinished).length}项</span>
/
<span>全部{this.state.list.length}项</span>
</div>
}
bordered
dataSource={this.state.list}
renderItem={(item) => (
<List.Item
actions={[
<Button
onClick={(e) => this.handleDelete(e, item)}
key='list-loadmore-edit'
type='danger'
style={{
display:
this.state.mouse.in === true && this.state.mouse.index === item.id
? 'inline-block'
: 'none',
}}>
删除
</Button>,
]}
onMouseOver={() => this.handleMouseOver(true, item)}
onMouseOut={() => this.handleMouseOver(false, item)}
onClick={() => this.handleFinish(item)}>
<Typography.Text mark={item.isFinished ? true : false}>
[ ]
</Typography.Text>
{item.text}
</List.Item>
)}
/>
</>
</div>
);
}
}