事件
这里的事件,指的是 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事件声明
- react事件采用
驼峰式
命名 - 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 事件执行 (即通过
onClick
和dom.addEventListener
绑定的事件,真实 DOM 事件会先执行;因为这个元素被点击时,真实 DOM 事件会很快找到,而 React 绑定的事件则需要去找到事件委托的元素,再去调用当前点击元素绑定的事件函数) - 过 React 事件阻止事件冒泡,无法阻止真实 DOM 事件的冒泡
- 可以使用
e.nativeEvent.stopImmediatePropagation()
去阻止 document 上剩余的事件处理程序的运行 (当我们在使用某些第三方库,在这个库有可能使用了一些事件处理,也对 document 绑定过点击事件,如:document.addEventListener("click", handler)
) - 在事件处理程序中,不要异步使用事件对象
e
;如果一定有异步使用的需求,则需要调用e.persist()
函数持久化保存此事件对象 (代价自然是损耗效率的)
React 事件总结
绑定事件处理函数
1.1 鼠标类
- onContextMenu
- onClick
- onDoubleClick
- onMouseDown
- onMouseUp
- onMouseEnter
- onMouseLeave
- onMouseMove
- onMouseOut
- onMouseOver
1.2 拖拽事件:
- onDrop
- onDrag
- onDragStart
- onDragEnd
- onDragEnter
- onDragLeave
- onDragOver
- onDragExit
1.3 触摸
触摸只会在移动设备上产生
- onTouchStart
- onTouchEnd
- onTouchMove
- onTouchCancel
1.4 键盘
onKeyPress是onKeyDown和onKeyUp的组合
- onKeyPress
- onKeyDown
- onKeyUp
剪切类
对应的是我们常常使用的复制
、剪切
和粘贴
- onCopy
- onCut
- onPaste
表单类
- onChange
- onInput
- onSubmit
- onChange可以用在输入框、单选框、下拉列表里,每当内容发生变化时我们都能获得通知。
onInput使用在文字输入。
onSubmit是用在整个表单的输入提交,常用在禁止表单的默认操作。
1.7 焦点事件
- onFocus
- onBlur
1.8 UI元素类
- onScroll
滚动事件触发的时候会触发onScroll事件
1.9 滚动
- onWheel
鼠标滚轮触发的事件,监听滚动幅度,滚动方位
1.10 组成事件
- onCompositionEnd
- onCompositionStart
- onCompositionUpdate
1.11 图片类
- onLoad
- onError
1.12 多媒体类
- onAbort
- onCanPlay
- onCanPlayThrough
- onDurationChange
- onEmptied
- onEncrypted
- onEnded
- onError
- onLoadedData
- onLoadedMetadata
- onLoadStart
- onPause
- onPlay
- onPlaying
- onProgress
- onRateChange
- onSeeked
- onSeeking
- onStalled
- onSuspend
- onTimeUpdate
- onVolumeChange
- 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 是事件对象的属性
通用属性
(以下内容括号内为类型)
- bubbles (boolean) 表示事件是否冒泡
- cancelable(boolean) 表示事件是否可以取消
- currentTarget(DOMEventTarget) 与Target类似,由于事件可以冒泡,所以两者表示的内容是不同的
- defaultPrevented(boolean) 表示事件是否禁止了默认行为
- eventPhase(number) 表示事件所处的阶段
- isTrusted(boolean) 表示事件是否可信。所谓的可信事件表示的是用户操作的事件,不可信事件就是通过JS代码来触发的事件。
- nativeEvent(DOMEvent)
- preventDefault() (void) 对应的defaultPrevented,表示的是禁止默认行为
- stopPropagaTion() (void) 对应的是bubbles,表示的是sh
- target(DOMEventTarget)
- timeStamp(number) 时间戳,也就是事件触发的事件
- type(string) 事件的类型
不同事件对象的特有属性
剪切事件
- clipboardData(DOMDataTransfer)表示拿到的数据
键盘事件
- ctrlKey(boolean) 表示是否按下ctrl键
- altKey(boolean) 表示是否按下alt键
- shiftKey(boolean) 表示是否按下shift
- metaKey(boolean) 表示的是win系统下的win键,mac系统下对应的command键
- getModifierState(key) (function) 表示是否按下辅助按键(辅助按键就是雷士ctrl、shift等辅助按键)可以传入按键编码来判断是否按下
- charCode(Number) 表示的是按键的字符编码,可以通过编码来判断按下的是什么键
- key(string) 字符串,按下的键
- keyCode(Number) 表示那些不是字符编码的按键
- which(Number) 表示经过通用化得charCode和keyCode
- locale(String) 表示本地化得一些字符串
- location(number) 表示位置
- repeat(boolean) 表示按键是否重复
焦点事件
- relatedTarget(DOMEventTarget) 相关焦点对象
鼠标事件
- ctrlKey(boolean)
- altKey(boolean)
- shiftKey(boolean)
- metaKey(boolean)
- getModifierState(key) (function)
- button(Number)
- buttons(Number)
- clientX(Number) 原点为浏览器左上角
- clinetY(Number) 原点为浏览器左上角
- pageX(Number) 原点为HTML页面的左上角
- pageY(Number) 原点为HTML页面的左上角
- screenX(Number) 原点为显示器的左上角
- screenY(Number) 原点为显示器的左上角
- relatedTarget(DOMEventTarget)
触摸事件
为了使触摸事件生效,在渲染所有组件之前调用 React.initializeTouchEvents(true)。
- ctrlKey(boolean)
- altKey(boolean)
- shiftKey(boolean)
- metaKey(boolean)
- getModifierState(key)
- changedTouches(DOMTouchList) 判断手势操作
- targetTouches(DOMTouchList) 判断手势操作
- touches(DOMTouchList) 判断手势操作
UI元素事件
- detail(Number) 滚动的距离
- view(DOMAbstractView) 界面,视窗
鼠标滚动
- deltaMode(Number) 可以理解为移动的单位
- deltaX(Number) X轴移动的相对距离固定值
- deltaY(Number) Y轴移动的相对距离固定值
- 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的事件对象是合成。
参考链接:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。