React组件化开发实现全选反选框

一、效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、实现步骤

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'))

输入 yarn start 启动项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值