关于前端:浅谈react事件处理

46次阅读

共计 9363 个字符,预计需要花费 24 分钟才能阅读完成。

事件

这里的事件,指的是 React 外部封装 DOM 组件中的事件,如 onClick, onFocus 等,而非咱们本人通过 props 传递的属性,并在子组件中手动触发的事件

实例

import React, {Component} from 'react';

class TodoList extends Component {render() {
        return (
            <div>
                <input type="text" />
                
                <button onClick={()=>{alert(1)
                }}>add</button>

                <button onClick={this.handelClick}>add2</button>
                
                <button onClick={this.handelClick2}>add3</button>

                <button onClick={()=>{this.handelClick3()
                }}>add4</button>
            </div>
        );
    }

    handelClick () {console.log(1)
        console.log(this)
    }

    // 箭头函数 
    handelClick2 = () => {console.log(2)
        console.log(this)
    }

    // 箭头函数 
    handelClick3 = () => {console.log(3)
        console.log(this)
    }
}

export default TodoList;

react 事件申明

  1. react 事件采纳 驼峰式 命名
  2. react 事件接管一个 函数申明 不是函数调用的模式
// 原生
<div onclick="handleClick()"></div>
//react
<div onClick={this.handleClick}></div>

绑定事件

采纳 on+ 事件名的形式 来绑定一个事件.

留神,这里和原生的事件是有区别的:
原生的事件全是小写 onclick , React 里的事件是 驼峰 onClick,React 的事件并不是原生事件,而是 合成事件

事件 handler 的写法

  • 间接在 render 里写行内的箭头函数(不举荐)
  • 在组件内应用 箭头函数 定义一个办法(举荐)
  • 间接在组件内 定义一个非箭头函数 的办法,而后在 render 里间接应用 onClick={this.handleClick.bind(this)} (不举荐)
  • 间接在组件内 定义一个非箭头函数 的办法,而后在 constructor 里 bind(this)(举荐)

Event 对象

和一般浏览器一样,事件 handler 会被主动传入一个 event 对象,这个对象和一般的浏览器 event 对象所蕴含的办法和属性都基本一致。不同的是 React 中的 event 对象并不是浏览器提供的,而是它 本人外部所构建的。它同样具备 event.stopPropagation event.preventDefault 这种罕用的办法.

this问题

实例

import React, {Component} from 'react';

class TodoList extends Component {render() {
        return (
            <div>
                <input type="text" />

                {/*:如果逻辑过不多,此写法举荐 */}
                {/* 能够间接拜访 this,无需手动绑定 */}
                <button onClick={()=>{console.log(0)
                     console.log(this)
                }}>add</button>

                {/*:此写法不举荐 */}
                {/* 不能够间接拜访 this,需手动绑定 --  .bind(this)*/}
                <button onClick={this.handelClick.bind(this)}>add2</button>
                
                {/*:此写法举荐 */}
                {/* 能够间接拜访 this,无需手动绑定,handelClick2 是箭头函数,能够绑定内部 this:此写法举荐 */}
                <button onClick={this.handelClick2}>add3</button>

                {/*:此写法比拟举荐,传参数很不便 */}
                {/* 能够间接拜访 this,无需手动绑定,onClick 调用的是箭头函数,能够绑定内部 this */}
                <button onClick={(e)=> this.handelClick3(e)}>add4</button>
            </div>
        );
    }

    handelClick () {console.log(1)
        console.log(this)
    }

    // 箭头函数 
    handelClick2 = (evt) => {console.log(2)
        console.log(this)
        
        // 打印 Event 对象
        console.log(evt)
    }

    // 箭头函数 
    handelClick3 = (evt) => {console.log(3)

        // 打印 Event 对象
        console.log(evt)
    }
}

export default TodoList;

为什么应用 bind 绑定 this

class 组件的事件绑定 this 问题

1. class 的办法 默认不会绑定 this,如果没有绑定 this.handleClick 的 this 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined。

class A extends React.Component{constructor(props){super(props)    
    }
    handleClick(){
        //class 的办法默认不会绑定 `this`,this 的指向依据调用的形式判断
        // 没有绑定调用的话 this 为 undefined
        this.setState({a:1})
    }
    render(){
        return (<div onClick={this.handleClick}></div>
        )
    }
}

this 问题的解决形式有三种

(1)在 constructor 里应用 bind 为办法绑定 this

class A extends React.Component{constructor(props){super(props)
        this.handleClick= this.handleClick.bind(this);    // 留神此处
    }
    handleClick(){this.setState({a:1})
    }
}

(2)在元素上绑定事件时应用 箭头函数


class A extends React.Component{constructor(props){super(props)    
    }
    handleClick(){
        //class 的办法默认不会绑定 `this`,this 的指向依据调用的形式判断
        // 没有绑定调用的话 this 为 undefined
        this.setState({a:1})
    }
    render(){
        //render 里的 this 指向本身
        return (<div onClick={()=> this.handleClick()}></div>
        )
    }
}

(3)应用 箭头函数 申明办法

class A extends React.Component{constructor(props){super(props)    
    }
    handleClick=()=>{
        // 箭头函数的 this 由父作用域的 this 判断
        this.setState({a:1})
    }
    render(){
        //render 里的 this 指向本身
        return (<div onClick={this.handleClick}></div>
        )
    }
}

react 事件 传递参数

1. 要在绑定事件的地位给事件传参有两种形式,

(1)通过 bind,应用bind 会隐式传入 事件对象 e ,作为函数的最初一个参数。

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

(2)通过 箭头函数 ,应用箭头函数须要 被动传入事件对象e。

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

事件阐明

React 依据 W3C 标准定义了合成事件 (SyntheticEvent),咱们就 无需放心跨浏览器的兼容性问题
React 出于性能与事件治理方面的考量,在之前的 React 版本中 (v17 之前)

  • 会将在 JSX 中注册的事件收集到 document 上 (即通过 事件委托 ,在 document 上注册事件,等触发事件时,则按 虚构 DOM 树 的构造进行事件触发机制去散发事件);
  • 简直所有的事件处理,均在 document 的事件中解决

    • 比方 onFocus 等事件不会冒泡的事件,就不做委托,间接在元素上监听
    • 一些 document 上没有的事件,也间接在元素上监听 (如:audio、video 标签的事件等)
  • 在 document 中的事件处理,会依据虚构 DOM 树的构造实现事件函数的调用,默认是 冒泡机制 (事件捕捉要通过相似 onClickCapture 的形式注册)
  • React 的事件参数,并非实在的事件参数,而是 React 合成的一个对象 (SyntheticEvent)

    • 通过调用 e.stopPropagation() 阻止事件冒泡 (仅阻止 React 事件)
    • 通过 e.nativeEvent 能够失去实在的 DOM 事件对象 (不过很少会用到)
    • 为了提高效率,React 应用事件 对象池 来处理事件对象 (即事件对象会重用)
  • 在 React 17 之后,事件委托的节点就转移到了渲染的根节点上,而且也帮咱们解决了此类对于事件冒泡的问题 (本文测试用例则阐明,对于应用 ReactDOM.createPortal 创立的组件,体现上略有差别)

留神点

  • 若给实在 DOM 注册事件,并阻止冒泡,则很有可能导致 React (JSX) 中注册的相干事件无奈触发
  • 若给实在 DOM 注册事件,它会先于 React 事件执行 (即通过 onClickdom.addEventListener 绑定的事件,实在 DOM 事件会先执行;因为这个元素被点击时,实在 DOM 事件会很快找到,而 React 绑定的事件则须要去找到事件委托的元素,再去调用以后点击元素绑定的事件函数)
  • 过 React 事件阻止事件冒泡,无奈阻止实在 DOM 事件的冒泡
  • 能够应用 e.nativeEvent.stopImmediatePropagation() 去阻止 document 上残余的事件处理程序的运行 (当咱们在应用某些第三方库,在这个库有可能应用了一些事件处理,也对 document 绑定过点击事件,如: document.addEventListener("click", handler))
  • 在事件处理程序中,不要异步应用事件对象 e;如果肯定有异步应用的需要,则须要调用 e.persist() 函数长久化保留此事件对象 (代价天然是损耗效率的)

React 事件总结

绑定事件处理函数

1.1 鼠标类

  1. onContextMenu
  2. onClick
  3. onDoubleClick
  4. onMouseDown
  5. onMouseUp
  6. onMouseEnter
  7. onMouseLeave
  8. onMouseMove
  9. onMouseOut
  10. onMouseOver

1.2 拖拽事件:

  1. onDrop
  2. onDrag
  3. onDragStart
  4. onDragEnd
  5. onDragEnter
  6. onDragLeave
  7. onDragOver
  8. onDragExit

1.3 触摸

触摸只会在挪动设施上产生

  1. onTouchStart
  2. onTouchEnd
  3. onTouchMove
  4. onTouchCancel

1.4 键盘

onKeyPress 是 onKeyDown 和 onKeyUp 的组合

  1. onKeyPress
  2. onKeyDown
  3. onKeyUp

剪切类

对应的是咱们经常应用的 复制 剪切 粘贴

  1. onCopy
  2. onCut
  3. onPaste

表单类

  1. onChange
  2. onInput
  3. onSubmit
  4. onChange 能够用在输入框、单选框、下拉列表里,每当内容发生变化时咱们都能取得告诉。

onInput 应用在文字输出。

onSubmit 是用在整个表单的输出提交,罕用在禁止表单的默认操作。

1.7 焦点事件

  1. onFocus
  2. onBlur

1.8 UI 元素类

  1. onScroll

滚动事件触发的时候会触发 onScroll 事件

1.9 滚动

  1. onWheel

鼠标滚轮触发的事件,监听滚动幅度,滚动方位

1.10 组成事件

  1. onCompositionEnd
  2. onCompositionStart
  3. onCompositionUpdate

1.11 图片类

  1. onLoad
  2. onError

1.12 多媒体类

  1. onAbort
  2. onCanPlay
  3. onCanPlayThrough
  4. onDurationChange
  5. onEmptied
  6. onEncrypted
  7. onEnded
  8. onError
  9. onLoadedData
  10. onLoadedMetadata
  11. onLoadStart
  12. onPause
  13. onPlay
  14. onPlaying
  15. onProgress
  16. onRateChange
  17. onSeeked
  18. onSeeking
  19. onStalled
  20. onSuspend
  21. onTimeUpdate
  22. onVolumeChange
  23. onWaiting

事件池

虚构事件对象曾经被合并。这意味着虚构事件对象将被从新应用,而该事件回调被调用之后所有的属性将有效。这是出于性能的思考。因而,您不能以异步的形式拜访事件。

function onClick(event) {console.log(event); // => 有效的对象
  console.log(event.type); // => "click"
  var eventType = event.type; // => "click"

  setTimeout(function() {console.log(event.type); // => null
    console.log(eventType); // => "click"
  }, 0);

  this.setState({clickEvent: event}); // 不起作用.this.state.clickEvent 将只蕴含空值.
  this.setState({eventType: event.type}); // 您仍然能够导出事件属性
}

如果您想以一个异步的形式来拜访事件属性,您应该对事件调用event.persist()。这将从事件池中取出合成的事件,并容许该事件的援用,使用户的代码被保留。

事件对象

事件处理器将会传入 SyntheticEvent 的实例,一个对浏览器本地事件的跨浏览器封装。它有和浏览器本地事件有雷同的属性和办法,包含stopPropagation()preventDefault(),然而没有浏览器兼容问题。

如果因为一些因素,须要底层的浏览器事件对象,只有应用 nativeEvent 属性就能够获取到它了。

对于 v0.14,在事件处理函数中返回 false 将不会阻止事件冒泡。取而代之的是在适合的利用场景下,手动调用 e.stopPropagation()或者e.preventDefault()

handleChange:function(e){console.log(e.target.value);
}

其中target 是 事件对象 e 是事件对象的属性

通用属性

(以下内容括号内为类型)

  1. bubbles (boolean) 示意事件是否冒泡
  2. cancelable(boolean) 示意事件是否能够勾销
  3. currentTarget(DOMEventTarget) 与 Target 相似,因为事件能够冒泡,所以两者示意的内容是不同的
  4. defaultPrevented(boolean) 示意事件是否禁止了默认行为
  5. eventPhase(number) 示意事件所处的阶段
  6. isTrusted(boolean) 示意事件是否可信。所谓的可信事件示意的是用户操作的事件,不可信事件就是通过 JS 代码来触发的事件。
  7. nativeEvent(DOMEvent)
  8. preventDefault() (void) 对应的 defaultPrevented,示意的是禁止默认行为
  9. stopPropagaTion() (void) 对应的是 bubbles,示意的是 sh
  10. target(DOMEventTarget)
  11. timeStamp(number) 工夫戳,也就是事件触发的事件
  12. type(string) 事件的类型

不同事件对象的特有属性

剪切事件
  1. clipboardData(DOMDataTransfer)示意拿到的数据
键盘事件
  1. ctrlKey(boolean) 示意是否按下 ctrl 键
  2. altKey(boolean) 示意是否按下 alt 键
  3. shiftKey(boolean) 示意是否按下 shift
  4. metaKey(boolean) 示意的是 win 零碎下的 win 键,mac 零碎下对应的 command 键
  5. getModifierState(key) (function) 示意是否按下辅助按键(辅助按键就是雷士 ctrl、shift 等辅助按键)能够传入按键编码来判断是否按下
  6. charCode(Number) 示意的是按键的字符编码,能够通过编码来判断按下的是什么键
  7. key(string) 字符串,按下的键
  8. keyCode(Number) 示意那些不是字符编码的按键
  9. which(Number) 示意通过通用化得 charCode 和 keyCode
  10. locale(String) 示意本地化得一些字符串
  11. location(number) 示意地位
  12. repeat(boolean) 示意按键是否反复
焦点事件
  1. relatedTarget(DOMEventTarget) 相干焦点对象
鼠标事件
  1. ctrlKey(boolean)
  2. altKey(boolean)
  3. shiftKey(boolean)
  4. metaKey(boolean)
  5. getModifierState(key) (function)
  6. button(Number)
  7. buttons(Number)
  8. clientX(Number) 原点为浏览器左上角
  9. clinetY(Number) 原点为浏览器左上角
  10. pageX(Number) 原点为 HTML 页面的左上角
  11. pageY(Number) 原点为 HTML 页面的左上角
  12. screenX(Number) 原点为显示器的左上角
  13. screenY(Number) 原点为显示器的左上角
  14. relatedTarget(DOMEventTarget)
触摸事件

为了使触摸事件失效,在渲染所有组件之前调用 React.initializeTouchEvents(true)。

  1. ctrlKey(boolean)
  2. altKey(boolean)
  3. shiftKey(boolean)
  4. metaKey(boolean)
  5. getModifierState(key)
  6. changedTouches(DOMTouchList) 判断手势操作
  7. targetTouches(DOMTouchList) 判断手势操作
  8. touches(DOMTouchList) 判断手势操作
UI 元素事件
  1. detail(Number) 滚动的间隔
  2. view(DOMAbstractView) 界面,视窗
鼠标滚动
  1. deltaMode(Number) 能够了解为挪动的单位
  2. deltaX(Number) X 轴挪动的绝对间隔固定值
  3. deltaY(Number) Y 轴挪动的绝对间隔固定值
  4. deltaZ(Number) Z 轴挪动的绝对间隔固定值

实例

滚动事件对象

var HelloDada = React.creatClass({getInitialState:function(){
        return {backgroundColor:'#FFFFFF'}
    },
    handleWheel:function(e){var newColor = (parseInt(this.state.backgroundColor.substr(1),16)+e.deltaY*997).tiString(16);
        this.setState({backgroundColor:newColor})
    },
    render:function(){return <div onWheel={this.handleWheel} style={this.state}> // 留神这里 onWheel
        <p>Dada Shuaige</p> 
        </div>
    }
});
ReactDOM.render(<HelloDada />,document.body)

键盘事件对象

var Dada =React.creatClass{getInitialState:function(){
        return{password:''}
    },
    handleKeyPress:function(e){
        this.setState({paddword:this.state.password+e.which});
    },
    handleChange:function(e){e.target.value='';},
    render:function(){
        return <div>
        <input onKeyPress={this.handleKeyPress} onChange={this.handleChange} /> // 留神这里 onKeyPress
        <p style={{'display':this.state.password.indexOf('495051') >=0?'block':'none'
        }}>Dada handsomeboy</p>
        </div>
    }
};
ReactDOM.render(<Dada />,document.body)

事件与状态关联

状态不仅仅实现了组件外部后果的清晰对应,还实现了组件与用户之间的交互,使用户与组件的行为紧紧联合起来

handleChange:function(e){this.setState({Dada:e.target.value});
}

this.setState设置状态

实例

var Dada =React.creatClass({getInitialState:function(){
        return{
            x:0,
            y:0
        }
    },
    handleMouseMove:function(e){
        this.setState({
            x:e.clientX,
            y:e.clientY
        });
    },
    render:function(){return <div onMouseMove={this.handleMouseMove} style={{  // 留神这里 onMouseMove
            width:'200px',
            height:'200px',
            backgroundColor:'#999'
        }}>
        {this.state.x+'.'+this.state.y}
        </div>
    }
});
ReactDOM.render(<Dada />,document.body)

React 绑定事件和原生绑定事件的区别

react 事件和原生事件的区别是:

  • react 中的事件是 绑定到 document 下面 , React 并不会真正的绑定事件到每一个具体《》的元素上,而是 采纳事件代理 的模式:
  • 而原生的事件是 绑定到 dom 下面

绝对绑定的中央来说,dom 上的事件要优先于 document 上的事件执行,react 的事件对象是合成。

参考链接:

  • https://blog.csdn.net/qq_40340943/article/details/107309779
  • https://www.bbsmax.com/A/Gkz1PBOgdR/

正文完
 0