onchange事件实现编辑_教程11——ref 及键盘事件--完成 todoList

369b388c52901b326042491b3d11047c.png

前言:我们一般在输入框中输入文字,点击添加按钮实现;但有些人不想用鼠标去点击,直接输入完成后回车,也是可以实现的,这就是键盘事件。

一、键盘事件(回车...)

TodoInput 文件:

import React, { Component } from 'react'

export default class TodoInput extends Component {
    static defaultProps={
        btnText:'添加TODO'
    }
    constructor(){
        super()
        this.state={
            inputValue:''
        }
    }
    handleInputChange = (e) => {
        this.setState({
            inputValue:e.currentTarget.value
        })
    }
    handleAddClick = (e) => {
        console.log(e)     //试试
        this.props.addTodo(this.state.inputValue)  //子组件向父组件传递
    }

    render() {
        return (
            <div>
                <input
                  type="text"
                  value={this.state.inputValue} 
                  onChange={this.handleInputChange}
                  onKeyUp={this.handleAddClick}           //这里!!!
                  />
                <button onClick={this.handleAddClick}>
                    {this.props.btnText}
                </button>
            </div>
        )
    }
}

结果:在输入的时候会发现,它就已经获取了,并没有通过回车键,所以这样做是不对的。

TodoInput 文件:(正确写法)

import React, { Component } from 'react'

export default class TodoInput extends Component {
    // static propTypes={
    //     btnText:propTypes.string
    // }
    static defaultProps={
        btnText:'添加TODO'
    }
    constructor(){
        super()
        this.state={
            inputValue:''
        }
    }
    handleInputChange = (e) => {
        this.setState({
            inputValue:e.currentTarget.value
        })
    }
    handleKeyUp = (e) => {            //回车事件
        if(e.keyCode === 13){
            this.handleAddClick()
        }
    }
    handleAddClick = (e) => {
        this.props.addTodo(this.state.inputValue)  //子组件向父组件传递
    }

    render() {
        return (
            <div>
                <input
                  type="text"
                  value={this.state.inputValue} 
                  onChange={this.handleInputChange}   //点击事件
                  onKeyUp={this.handleKeyUp}          //回车事件
                  />
                <button onClick={this.handleAddClick}>
                    {this.props.btnText}
                </button>
            </div>
        )
    }
}

结果回车、添加按钮都可以实现

二、ref

react 里面通过 ref 来获取组件或者 dom 元素

要使用 ref 之前必需先调 React.createRef 方法来创建一个 ref

在 constructor 里创建 ref,我们把创建的结果赋值给一个 this

import React, { Component,createRef } from 'react'

TodoInput 文件:

import React, { Component,createRef } from 'react'

export default class TodoInput extends Component {
    // static propTypes={
    //     btnText:propTypes.string
    // }
    static defaultProps={
        btnText:'添加TODO'
    }
    constructor(){
        super()
        this.state={
            inputValue:''
        }
        this.inputDom=createRef()   //创建ref
    }
    handleInputChange = (e) => {
        this.setState({
            inputValue:e.currentTarget.value
        })
    }
    handleKeyUp = (e) => {            //回车事件
        if(e.keyCode === 13){
            this.handleAddClick()
        }
    }
    handleAddClick = (e) => {

        //实际项目会对this.state.inputValue做验证,验证通过才继续执行下面的方法

        if (this.state.inputValue === '') {
            return
        }
        this.props.addTodo(this.state.inputValue)  //子组件向父组件传递
        this.setState({
            inputValue:''
        },() => {
            this.inputDom.current.focus()
        })
    }

    render() {
        return (
            <div>
                <input
                  type="text"
                  value={this.state.inputValue} 
                  onChange={this.handleInputChange}   //点击事件
                  onKeyUp={this.handleKeyUp}          //回车事件
                  ref={this.inputDom}        //ref
                  />
                <button onClick={this.handleAddClick}>
                    {this.props.btnText}
                </button>
            </div>
        )
    }
}

三、删除事件

应该写在 App.js 文件里面:通过 TodoList 把事件继续往下传递

四、改变完成、未完成状态

TodoItem 文件:

import React, { Component } from 'react'

export default class TodoItem extends Component {
    handleCheckboxChange = () =>{
        // console.log('changed')
        this.props.onCompeletedChange()
        
    }
    render() {
        return (
            <li>
                <input
                  checked={this.props.isCompleted}
                  onChange={this.handleCheckboxChange}
                  type="checkbox"
                />
                <span>{this.props.title}{this.props.isCompleted ? '完成' : '未完成'}</span>
            </li>
        )
    }
}

App.js 文件:

import React, { Component } from 'react'
import{
    TodoHeader,
    TodoInput,
    TodoList,
    Like
} from './components'

export default class App extends Component {
    // state = {
    //     title:'待办事项列表'
    // }

    constructor(){
        super()
        this.state={
            title:'待办事项列表',
            desc:'今日事,今日毕',
            todos:[{
                id:1,
                title:'吃饭',
                assignee:'FatBaby',
                article:'<div>aaaaaa</div><i>bbbbb</i>',
                isCompleted:true
            },{
                id:2,
                title:'睡觉',
                assignee:'HeiWa',
                isCompleted:false
            }]
        }
    }

    addTodo = (TodoTitle) => {     //TodoInput 里面去执行这个方法
        console.log(TodoTitle)
        // this.setState({
        //     todos:this.state.todos.concat({
        //         id:Math.random(),
        //         title:TodoTitle,
        //         isCompleted:false
        //     })
        // })

        const newTodos=this.state.todos.slice()   //重新复制一份数组
        newTodos.push({
            id:Math.random(),
            title:TodoTitle,
            isCompleted:false
        })
        this.setState({
            todos:newTodos
        })  
    }

    onCompeletedChange = () =>{
        console.log('onCompeletedChange');
        
    }

    render() {
        return (
            <>
                <TodoHeader desc={this.state.desc}>
                    {this.state.title}
                </TodoHeader>
                <TodoInput
                 addTodo={this.addTodo}
                />
                <TodoList
                  todos={this.state.todos}
                  onCompeletedChange={this.onCompeletedChange}
                 /> 
                <Like />
            </>
        )
    }
}

TodoList 文件:

import React, { Component } from 'react'
import TodoItem from './TodoItem'
import PropTypes from 'prop-types'

export default class TodoList extends Component {
    static propTypes={
        todos:PropTypes.arrayOf(PropTypes.shape({
            id:PropTypes.number.isRequired,
            title:PropTypes.string.isRequired,
            isCompleted:PropTypes.bool.isRequired
        })).isRequired,
        onCompeletedChange:PropTypes.func
    }
    render() {
        return (
            <ul>
                {
                    this.props.todos.map(todo => {
                        return(
                            // <TodoItem
                            //   key={todo.id}
                            //   id={todo.id}
                            //   title={todo.title}
                            //   assignee={todo.assignee}
                            //   isCompleted={todo.isCompleted}
                            // />
                            <TodoItem
                              onCompeletedChange={this.props.onCompeletedChange}
                              key={todo.id}
                              {...todo}
                            />
                        )
                    })
                }
            </ul>
        )
    }
}

7f4d9f44cf17af068c3b5f479567eb6d.png
结果:当我想改变它的‘完成’状态,点击后执行了

现在做成可以点击的状态

App.js 文件:

import React, { Component } from 'react'
import{
    TodoHeader,
    TodoInput,
    TodoList,
    Like
} from './components'

export default class App extends Component {
    constructor(){
        super()
        this.state={
            title:'待办事项列表',
            desc:'今日事,今日毕',
            todos:[{
                id:1,
                title:'吃饭',
                assignee:'FatBaby',
                article:'<div>aaaaaa</div><i>bbbbb</i>',
                isCompleted:true
            },{
                id:2,
                title:'睡觉',
                assignee:'HeiWa',
                isCompleted:false
            }]
        }
    }

    addTodo = (TodoTitle) => {                            //TodoInput 里面去执行这个方法
        const newTodos=this.state.todos.slice()           //重新复制一份数组
        newTodos.push({
            id:Math.random(),
            title:TodoTitle,
            isCompleted:false
        })
        this.setState({
            todos:newTodos
        })  
    }

    onCompeletedChange = (id) =>{
        console.log('onCompeletedChange',id);             //获取到id
        this.setState((prevState) => {                    //可以点击按钮
            return{
                todos:prevState.todos.map(todo =>{
                    if(todo.id === id){
                        todo.isCompleted=!todo.isCompleted
                    }
                    return todo
                })
            }
        })
    }

    render() {
        return (
            <>
                <TodoHeader desc={this.state.desc}>
                    {this.state.title}
                </TodoHeader>
                <TodoInput
                 addTodo={this.addTodo}
                />
                <TodoList
                  todos={this.state.todos}
                  onCompeletedChange={this.onCompeletedChange}       //!!!!
                 /> 
                <Like />
            </>
        )
    }
}

结果:是可以点击的状态了

那如果我这里没有传这个东西呢??

 onCompeletedChange={this.onCompeletedChange}

报错是肯定的啊,那怎么改

那咱们去调用这个东西之前是不是应该去做一个判断

this.props.onCompeletedChange && this.props.onCompeletedChange(this.props.id)

一般我们会这样来写

const{
            onCompeletedChange,
            id
        }=this.props
        onCompeletedChange && onCompeletedChange(id)

或者

const{
            onCompeletedChange = () => {},
            id
        }=this.props
        onCompeletedChange(id)
    }

最终代码(完整版)

TodoItem 文件:

import React, { Component } from 'react'

export default class TodoItem extends Component {
    handleCheckboxChange = () =>{
        // console.log('changed')

        // this.props.onCompeletedChange && this.props.onCompeletedChange(this.props.id)

        const{       //解构
            onCompeletedChange = noop,          //noop 其实就是一个空函数
            id
        }=this.props
        onCompeletedChange(id)
    }
    render() {
        const{     //解构,代码写起来更方便
            isCompleted,
            title
        }=this.props

        return (
            <li>
                <input
                  checked={isCompleted}
                  onChange={this.handleCheckboxChange}
                  type="checkbox"
                />
                <span>{title}{isCompleted ? '完成' : '未完成'}</span>
            </li>
        )
    }
}

App.js 文件:

import React, { Component } from 'react'
import{
    TodoHeader,
    TodoInput,
    TodoList,
    Like
} from './components'

export default class App extends Component {
    // state = {
    //     title:'待办事项列表'
    // }

    constructor(){
        super()
        this.state={
            title:'待办事项列表',
            desc:'今日事,今日毕',
            todos:[{
                id:1,
                title:'吃饭',
                assignee:'FatBaby',
                article:'<div>aaaaaa</div><i>bbbbb</i>',
                isCompleted:true
            },{
                id:2,
                title:'睡觉',
                assignee:'HeiWa',
                isCompleted:false
            }]
        }
    }

    addTodo = (TodoTitle) => {     //TodoInput 里面去执行这个方法
        console.log(TodoTitle)
        // this.setState({
        //     todos:this.state.todos.concat({
        //         id:Math.random(),
        //         title:TodoTitle,
        //         isCompleted:false
        //     })
        // })

        const newTodos=this.state.todos.slice()   //重新复制一份数组
        newTodos.push({
            id:Math.random(),
            title:TodoTitle,
            isCompleted:false
        })
        this.setState({
            todos:newTodos
        })  
    }

    onCompeletedChange = (id) =>{
        console.log('onCompeletedChange',id);   //获取到id
        this.setState((prevState) => {   //点击按钮
            return{
                todos:prevState.todos.map(todo =>{
                    if(todo.id === id){
                        todo.isCompleted=!todo.isCompleted
                    }
                    return todo
                })
            }
        })
    }

    render() {
        return (
            <>
                <TodoHeader desc={this.state.desc}>
                    {this.state.title}
                </TodoHeader>
                <TodoInput
                 addTodo={this.addTodo}
                />
                <TodoList
                  todos={this.state.todos}
                //  onCompeletedChange={this.onCompeletedChange}
                 /> 
                <Like />
            </>
        )
    }
}

over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值