一、效果展示
二、实现步骤
1.通过 create-react-app 初始化项目
2.拆分组件
List组件:包含选项
Item组件:选项
CheckAll:全选反选
Footer:展示被选项
文件结构如下:
3.各组件代码
App.jsx
import React, { Component } from 'react'
import './App.css'
import List from './components/List'
import CheckAll from './components/CheckAll'
import Footer from './components/Footer'
export default class App extends Component {
// 初始化状态
state = {
options: [
{ id: '001', name: '方便面', checked: true },
{ id: '002', name: '热干面', checked: true },
{ id: '003', name: '牛肉面', checked: false },
{ id: '004', name: '蟹脚面', checked: false }
]
}
// 更新选择框状态
updateChecked = (id, checked) => {
const { options } = this.state
const newOptions = options.map((optionObj) => {
if (optionObj.id === id) {
return { ...optionObj, checked: checked }
} else {
return optionObj
}
})
this.setState({ options: newOptions })
}
// 全选反选
checkAll = (checked) => {
const { options } = this.state
const newOptions = options.map((optionObj) => {
return { ...optionObj, checked: checked }
})
this.setState({ options: newOptions })
}
render() {
const { options } = this.state
return (
<div className="check-container">
<div className="check-wrap">
<List options={options} updateChecked={this.updateChecked} />
<CheckAll options={options} checkAll={this.checkAll} />
<Footer options={options} />
</div>
</div>
)
}
}
App.css
/* base */
body {
background: #fff;
}
.check-container {
width: 600px;
margin: 0 auto;
}
.check-container .check-wrap {
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
}
List组件
index.jsx
import React, { Component } from 'react'
import Item from '../Item'
import './index.css'
// 列表组件,包含选项
export default class List extends Component {
render() {
const { options, updateChecked } = this.props
return (
<ul className="check-main">
{
options.map(option => {
return <Item key={option.id} {...option} updateChecked={updateChecked} />
})
}
</ul>
)
}
}
index.css
/*main*/
.check-main {
margin-left: 0px;
border: 1px solid #ddd;
border-radius: 2px;
padding: 0px;
}
Item组件
index.jsx
import React, { Component } from 'react'
import './index.css'
// 选项组件
export default class Item extends Component {
// 标识鼠标移入移出
state = { mouse: false }
// 鼠标移入、移出的回调
handleMouse = (flag) => {
return () => {
this.setState({ mouse: flag })
}
}
// 更新选择框的回调
handleCheck = (id) => {
return (event) => {
this.props.updateChecked(id, event.target.checked)
}
}
render() {
const { mouse } = this.state
const { id, name, checked } = this.props
return (
<li style={{ backgroundColor: mouse ? '#ddd' : 'white' }} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)} >
<label>
<input type="checkbox" checked={checked} onChange={this.handleCheck(id)} />
<span>{name}</span>
</label>
</li>
)
}
}
index.css
/*item*/
li {
list-style: none;
height: 36px;
line-height: 36px;
padding: 0 5px;
border-bottom: 1px solid #ddd;
}
li label {
float: left;
cursor: pointer;
}
li label li input {
vertical-align: middle;
margin-right: 6px;
position: relative;
top: -1px;
}
li:before {
content: initial;
}
li:last-child {
border-bottom: none;
}
CheckAll组件
index.jsx
import React, { Component } from 'react'
import './index.css'
// 全选反选组件
export default class CheckAll extends Component {
// 全选反选的回调
handleCheckAll = (event) => {
return this.props.checkAll(event.target.checked)
}
render() {
const { options } = this.props
const checkedNum = options.reduce((pre, option) => pre + (option.checked ? 1 : 0), 0)
const total = options.length
return (
<div className="check-checkall">
<label>
<input type="checkbox" checked={(checkedNum === total && total !== 0 ? true : false)} onChange={this.handleCheckAll} />
</label>
<span>
<span>已选择{checkedNum}</span> / 全部{total}
</span>
</div>
)
}
}
index.css
/*footer*/
.check-checkall {
height: 40px;
line-height: 40px;
padding-left: 6px;
margin-top: 5px;
}
.check-checkall label {
display: inline-block;
margin-right: 20px;
cursor: pointer;
}
.check-checkall label input {
position: relative;
top: -1px;
vertical-align: middle;
margin-right: 5px;
}
Footer组件
index.jsx
import React, { Component } from 'react'
import './index.css'
// 已选择框组件
export default class Footer extends Component {
render() {
const { options } = this.props
return (
<div className='check-footer'>
<span>已选择:{options.map((optionObj) => { return optionObj.checked === true ? optionObj.name + ' ' : null })}</span>
</div>
)
}
}
index.css
无
渲染组件到页面 index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />,document.getElementById('root'))