react實現todolist的增刪改查詳解
以todolist為例
目錄如下
app.js
import React, { PureComponent } from 'react' import Input from './components/Input' import List from './components/List' import Total from './components/Total' import Mask from './components/Mask' import { bus as $bus } from './components/bus' import './App.css' export default class App extends PureComponent { constructor() { super() this.state = { flag: false, list: [ { id: 1, content: '哈哈哈', checked: false }, { id: 7, content: '哈哈哈', checked: false }, { id: 5, content: '哈哈哈', checked: false }, ], checkAll: false, selectLength: 0, item: {} } } // 全選全不選 checkAllHandler(checked) { console.log("checked",checked); const { list } = this.state const newList = list.map(item =>{ return {...item,checked} }) this.setState({list:newList,checkAll: checked},()=>{ this.doneLenth() }) } // 單選單不選 checkHandler =(id,checked)=> { const { list } = this.state const newList = list.map(item => { return item.id === id ? {...item,checked} : item }) let checkAll = newList.length && newList.every(item => item.checked) this.setState(() => ({list: newList,checkAll}),()=>{ this.doneLenth() }) } // 添加 addHandler = (obj)=>{ let { list } = this.state; let newList = [...list,obj] console.log('newList===='+newList) this.setState({ list: newList, },()=>{ this.doneLenth() }) } // 搜索 searchHandler=(content)=>{ console.log("content",content); let { list } = this.state; let newList = list.filter(item => item.content.includes(content)) this.setState({ list: newList },()=>{ this.doneLenth() }) } // 刪除 delHandler = (id)=> { console.log("id",id); const { list } = this.state const newList = list.filter(item => item.id !=id) let checkAll = newList.length && newList.every(item => item.checked) this.setState(() => ({list: newList,checkAll}),()=>{ this.doneLenth() }) } // 編輯 editHandler = (items)=>{ this.setState({ item: items }) } // 更新 update = (content)=>{ const { list,item } = this.state let obj = Object.assign(item,{content}) const newList = list.map(v =>{ if(v.id === obj.id) { v = {...obj} } return v }) this.setState({ list: newList, item: obj }) } // 已完成 doneLenth=()=> { const { list } = this.state const newList = list.filter(item => item.checked) let selectLength = newList.length setTimeout(()=>{ this.setState({ selectLength }) }) } // 掛載 componentDidMount() { this.unSubscribe = $bus.addListener("getFlag",(flag)=>{ this.setState({flag}) }) this.unSubscribe1 = $bus.addListener("sendValue",(obj)=>{ this.addHandler(obj) }) this.unSubscribe2 = $bus.addListener("searchValue",(value)=>{ this.searchHandler(value) }) this.unSubscribe3 = $bus.addListener("getItem",(item)=>{ this.editHandler(item) }) this.unSubscribe4 = $bus.addListener("update",(content)=>{ this.update(content) }) } // 卸載 componentWillUnmount() { $bus.removeListener(this.unSubscribe) $bus.removeListener(this.unSubscribe1) $bus.removeListener(this.unSubscribe2) $bus.removeListener(this.unSubscribe3) $bus.removeListener(this.unSubscribe4) } render() { let { flag, list,checkAll,selectLength } = this.state return ( <div className='container'> {/* 輸入框 */} <Input></Input> {/* 列表 */} <List list={list} checkHandler={this.checkHandler} delHandler={this.delHandler}></List> {/* 統計 */} <Total checkAllHandler={this.checkAllHandler.bind(this)} checkAll={checkAll} selectLength={selectLength}></Total> {/* 編輯彈框 */} { flag ? <Mask ></Mask> : ''} </div> ) } }
Input.js
import React, { Component } from 'react' import { bus as $bus } from './bus' export default class Input extends Component { constructor() { super() this.state = { value:"" } } changeHandler = (e)=>{ this.setState({ value: e.target.value }) console.log("this.state.value",this.state.value); } // 添加 addHandler = ()=>{ let { value } = this.state; let obj = { id: Date.now(), content: value, done: false } if(value) { $bus.emit("sendValue",obj) } else { console.log("請輸入") } } // 搜索 searchHandler = ()=>{ console.log("搜索"); let { value } = this.state; if(!value) return console.log("請輸入"); $bus.emit("searchValue",value) } render() { let { value } = this.state return ( <> <div className="input"> <input type="text" value={value} placeholder='請輸入你的任務名稱,按回車鍵確認' onInput={this.changeHandler}/> <button className="btn btn-success" onClick={this.addHandler}>添加</button> <button className="btn btn-primary" onClick={this.searchHandler}>搜索</button> </div> </> ) } }
List.js
import React, { Component } from 'react' import Item from './Item' import PropTypes from 'prop-types' export default class List extends Component { static propTypes = { list:PropTypes.array.isRequired, } render() { let { list,checkHandler,checkAllHandler,delHandler } = this.props; console.log("list",list); return ( <ul className="task-list"> { list.map(item => (<Item item={item} key={item.id} checkHandler={checkHandler} checkAllHandler={checkAllHandler} delHandler={delHandler}></Item>)) } </ul> ) } }
Item.js
import React, { Component } from 'react' import { bus as $bus } from './bus' export default class Item extends Component { constructor(props) { super(props) this.state = {} } changeHandler = (id)=>{ let { checkHandler } = this.props; return (e)=>{ checkHandler(id,e.target.checked) } } removeHandler(){ let { delHandler } = this.props; delHandler(arguments[0]) } editHadnler = (item)=>{ $bus.emit("getFlag",true) localStorage.setItem("obj",JSON.stringify(item)) $bus.emit("getItem",item) } render() { let { item } = this.props; return ( <li className="task-item"> <input type="checkbox" checked={item.checked} onChange={this.changeHandler(item.id)}/> <div className="content"> {item.content} </div> <button className={`btn btn-success ${!item.checked ? "d-none" : "d-block"}`} onClick={()=> this.editHadnler(item)}>編輯</button> <button className={`btn btn-danger ${!item.checked ? "d-none" : "d-block"}`} onClick={this.removeHandler.bind(this,item.id)}>刪除</button> </li> ) } }
Total.js
import React, { Component } from 'react' export default class Total extends Component { constructor() { super() this.changeAllHandler = this.changeAllHandler.bind(this) } changeAllHandler(e) { let { checkAllHandler } = this.props checkAllHandler(e.target.checked) } render() { let { checkAll,selectLength } = this.props; return ( <div className="task-done"> <input type="checkbox" onChange={this.changeAllHandler} checked={checkAll}/> <p>已完成<span className="single-number">{selectLength}</span> 全部<span className="all-number">4</span></p> </div> ) } }
Mask.js(彈窗)
import React, { Component } from 'react' import { bus as $bus } from './bus' export default class mask extends Component { constructor() { super() this.state = { value: '' } } closeMask = ()=>{ // 關閉彈窗 $bus.emit("getFlag",false) } updateHandler = ()=>{ $bus.emit("getFlag",false) $bus.emit("update",this.state.value) } onChange = (e) =>{ this.setState({ value: e.target.value }) } componentDidMount() { let obj = JSON.parse(localStorage.getItem("obj")) this.setState({ value: obj.content }) } render() { let { value } = this.state return ( <div> <div className="mm-mask" > <div className="mm-modal"> <div className="mm-title"> <span className="mm-edit">編輯</span> <span className="mm-close" onClick={this.closeMask}>x</span> </div> <div className="mm-content"> <input type="text" value={value} placeholder="任務名稱" onInput={this.onChange}/> </div> <div className="mm-box-btn"> <div className="mm-update" onClick={this.updateHandler}>更新</div> <div className="mm-cancel" onClick={this.closeMask}>取消</div> </div> </div> </div> </div> ) } }
bus.js
yarn add -D events import { EventEmitter } from 'events' export const bus = new EventEmitter() // 導出bus實例
App.css
* { margin: 0; padding: 0; } input,button { outline: none; border: 0; } ul>li { list-style: none; } .container { width: 400px; height: 500px; margin: 10px auto auto; padding: 20px; box-sizing: border-box; color: #3333; border: 1px solid; overflow: hidden; } .input { width: 100%; height: 30px; display: flex; } input { width: 100%; height: 100%; border: 1px solid #e1e1e1; box-sizing: border-box; border-radius: 4px; padding: 0 10px; } input::placeholder { color: #e1e1e1; } input:focus { border: 1px solid #0096e6; } .task-list { width: 100%; display: flex; flex-flow: column wrap; margin-top: 10px; } .task-list li { display: flex; height: 40px; justify-content: center; align-items: center; padding: 0 10px; background-color: #eef0f4; margin-bottom: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .task-list li input[type^="checkbox"] { width: 15px; height: 15px; border: 1px solid #e1e1e1; cursor: pointer; flex-shrink: 0; } .task-list li .content { flex: 1; margin-left: 10px; } .btn { flex-shrink: 0; display: flex; align-items: center; height: 30px; justify-content: center; padding: 5px 10px; text-align: center; cursor: pointer; border-radius: 4px; color: #fff; letter-spacing: 2px; margin: 0 5px; box-sizing: border-box; font-size: 16px; } .btn-success { background-color: #0f0; } .btn-danger { background-color: #f00; } .btn-primary { background-color: #0096e6; } .task-done { width: 100%; height: 40px; line-height: 40px; display: flex; align-items: center; background-color: #eef0f4; padding-left: 10px; box-sizing: border-box; margin-top: 30px; } .task-done input { width: 15px; height: 15px; border: 1px solid #e1e1e1; cursor: pointer; flex-shrink: 0; margin-right: 10px; } .single-number { color: #333; margin-left: 5px; } .all-number { color: red; margin-left: 5px; } .mm-mask{ position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.5); } .mm-modal{ width:350px; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:1000; background:#ffffff; border-radius:4px; color:#333333; } .mm-title { height:50px; line-height:50px; display:flex; justify-content:space-between; border-bottom:1px solid #e1e1e1; box-sizing:border-box; font-size:20px; } .mm-edit{ text-indent:20px; } .mm-close{ margin-right:20px; font-family:consals; cursor:pointer; } .mm-content{ padding:0 20px; margin-bottom:20px; } .mm-content input{ width:100%; height:30px; line-height:30px; text-indent:20px; border-radius:4px; margin-top:20px; border:1px solid #666; box-sizing:border-box; } .mm-content input:hover{ border:1px solid #0096e6; } .mm-content input:last-child{ text-indent:5px; } .mm-box-btn{ display:flex; } .mm-update,.mm-cancel{ width:80px; height:30px; line-height:30px; text-align: center; cursor:pointer; background:#0096e6; color:#ffffff; user-select:none; border-radius:4px; margin:0 20px 50px; } .mm-update{ margin-right:10px; } .d-none { display: none; } .d-block { display: block; }
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- react中使用forEach或map兩種方式遍歷數組
- react實現導航欄二級聯動
- 代碼解析React中setState同步和異步問題
- 使用react-virtualized實現圖片動態高度長列表的問題
- Vuex實現記事本功能