博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React 中的事件处理
阅读量:6715 次
发布时间:2019-06-25

本文共 6471 字,大约阅读时间需要 21 分钟。

基本使用

React框架自身实现了一套事件处理机制,它的基本用法和DOM事件很相似。例如,给某个react元素绑定点击事件:

图片描述

  • 事件类型采用小驼峰命名法,因此是 onClick,而不是 onclick,其他事件类型相同。
  • 直接将函数的声明当成事件句柄传递

我们将它的这套事件处理机制称之为SyntheticEvent,即合成事件

Synthetic Event

支持的事件类型

React支持的事件类型如下:

事件流

React中,默认的事件传播方式为冒泡

import React, { Component } from "react"import ReactDOM from "react-dom"const styles = {    child: {        width: "100px",        height: "100px",        backgroundColor: "red"    },    parent: {        width: "150px",        height: "150px",        backgroundColor: "blue"    },    ancestor: {        width: "200px",        height: "200px",        backgroundColor: "black"    }}class App extends Component {    render() {        return (            
{ console.log("ancestor") }} style={styles.ancestor}>
{ console.log("parent"); }} style={styles.parent}>
{ console.log("child"); }} style={styles.child}>
); }}ReactDOM.render(
, document.querySelector("#root"));

在该示例中,3div嵌套显示,并且每个元素上均绑定onClick事件:

图片描述

当用户点击红色区域的div元素时,可以看到,控制台先后输出了child -> parent -> ancestor,这是因为在React的事件处理系统中,默认的事件流就是冒泡,如果说我们希望以捕获的方式来触发事件的话,可以使用onClickCapture来绑定事件,也就是在事件类型后面加一个后缀Capture

import React, { Component } from "react"import ReactDOM from "react-dom"const styles = {    child: {        width: "100px",        height: "100px",        backgroundColor: "red"    },    parent: {        width: "150px",        height: "150px",        backgroundColor: "blue"    },    ancestor: {        width: "200px",        height: "200px",        backgroundColor: "black"    }}class App extends Component {    render() {        return (            
{ console.log("ancestor") }} style={styles.ancestor}>
{ console.log("parent"); }} style={styles.parent}>
{ console.log("child"); }} style={styles.child}>
); }}ReactDOM.render(
, document.querySelector("#root"));

这时,还是点击红色区域的div,就可以看到事件流是从ancestor -> parent -> child 传播了。

图片描述

事件委托

在合成事件系统中,所有的事件都是绑定在document元素上,即,虽然我们在某个react元素上绑定了事件,但是,最后事件都委托给document统一触发。

图片描述

在合成事件中只能阻止合成事件中的事件传播

我们在红色区域的div里,也就是最里层的那个元素上,使用e.stopPropagation()方法来阻止事件流的传播:

{ console.log("ancestor") }} style={styles.ancestor}>
{ console.log("parent"); }} style={styles.parent}>
{ console.log("child"); e.stopPropagation(); }} style={styles.child}>

点击红色区域的,我们可以看到控制台上只输出了child,说明这时已经成功阻止了冒泡。执行流程如下:

图片描述

从图中我们可以看到,react 阻止的事件流,并没有阻止真正DOM元素的事件触发,当红色div元素被点击时,真正的元素还是按照冒泡的方式,层层将事件交给上级元素进行处理,最后事件传播到docuement,触发合成事件,在合成事件中,child触发时,e.stopPropagation();被调用,合成事件中的事件被终止。因此,合成事件中的stopPropagation无法阻止事件在真正元素上的传递,它只阻止合成事件中的事件流。相反,如果我们在红色的div上,绑定一个真正的事件,那么,合成事件则会被终止。

图片描述

事件对象

SyntheticEvent中,我们依然可以获取到事件发生时的event对象:

import React, { Component } from "react"import ReactDOM from "react-dom"const styles = {  "DEBUG_DISPLAY": {    width: "150px",    height: "150px",    backgroundColor: "red"  }}class App extends Component {  state = {    x: 0,    y: 0  }  render() {    return (      
{ console.log(e) }} > x: {this.state.x},y: {this.state.y}
); }}ReactDOM.render(
, document.querySelector("#root"));

以上示例中,我们给div元素绑定了一个click事件,在用户点击时,在控制台输出event对象:

图片描述

接下来将用户点击时的坐标在div元素中显示出来,可以通过clientXclientY来访问:

{ this.setState({ x: e.clientX, y: e.clientY }); }} > x: {this.state.x},y: {this.state.y}

合成事件中的event对象,并不是原生的event,只是说,我们可以通过它获取到原生event对象上的某些属性,比如以上示例中的clientXclientY。而且,对于这个event对象,在整个合成事件中,只有一个,被全局共享,也就是说,当这次事件调用完成之后,这个event对象会被清空,等待下一次的事件触发,因此,我们无法在异步的操作中获取到event

{ setTimeout(() => { this.setState({ x: e.clientX, y: e.clientY }); }, 1000); }} > x: {this.state.x},y: {this.state.y}

当用户点击div1秒之后获取点击时的坐标,这时,可以看到控制台抛出错误:

图片描述

在异步操作中想要获取event对象中的数据,在事件发生时就需要将数据通过变量保存下来:

{ const { clientX, clientY } = e; setTimeout(() => { this.setState({ x: clientX, y: clientY }); }, 1000); }} > x: {this.state.x},y: {this.state.y}

混合使用

react鼓励我们使用合成事件,但是,在某些需求中,还是需要通过原生事件来进行处理,这时,就涉及到合成事件和原生事件的混合使用,例如以下示例:

import React, { Component } from "react"import ReactDOM from "react-dom"class App extends Component {  state = {    isShow: "none"  }  render() {    return (      
); }}ReactDOM.render(
, document.querySelector("#root"));

在这个示例中,我们提供一个按钮和一个div元素,当用户点击按钮时,显示div,当点击页面其他区域时,则隐藏。以上代码已经实现点击按钮显示div的功能:

图片描述

要实现 点击其他区域隐藏div元素 的功能,需要将事件绑定在document元素上,接下来,在compnentDidMount生命周期函数中,来绑定该事件:

class App extends Component {  state = {    ...  }  componentDidMount() {    document.addEventListener("click", e => {        this.setState({            isShow: "none"        });    })  }  render() {    ...  }}

当点击按钮时,isShow: "block",当点击其他区域时,isShow: "none"。这时我们发现,点击按钮时,div显示不出来了。

图片描述

这个现象的原因是,实际上,在document元素身上,现在已经存在2click事件,一个是合成事件绑定的click,另外一个是我们自己添加的监听器。当用户点击按钮时,synthetic中的click首先被触发,这时,isShow状态被设置成block,页面元素被显示出来,紧跟着,native中的click事件被触发,又把isShow的状态改为nonediv元素又被隐藏了起来。

处理方法:

import React, { Component } from "react"import ReactDOM from "react-dom"class App extends Component {  state = {    isShow: "none"  }  button = React.createRef();  componentDidMount() {    document.addEventListener("click", e => {      // 当 native 事件被触发时,我们判断一下当前目标元素是否为 button,      // 如果不是点击的按钮,则就意味着将元素隐藏      if (e.target !== this.button.current) {        this.setState({          isShow: "none"        });      }    })  }  render() {    return (      
); }}ReactDOM.render(
, document.querySelector("#root"));

转载地址:http://caelo.baihongyu.com/

你可能感兴趣的文章
实现大屏幕全国监控各地流量和负载质量
查看>>
高性能HTTP加速器Varnish(安装配置篇)
查看>>
如何取消OneNote的粘贴来源地址
查看>>
编程乐趣:C#实现读取12306余票信息
查看>>
视频编码的常见参数基本概念
查看>>
用python写一个专业的传参脚本
查看>>
Nginx+PHP7 安装及配置
查看>>
OpenIndiana
查看>>
varnish基础概念详解
查看>>
发一个windows8 下QQ应用的测试报告-精彩截图
查看>>
利用Zabbix ODBC monitoring监控MySQL
查看>>
如何设计一款优秀的短视频 SDK
查看>>
实战postfix邮件发送
查看>>
MySQL主从架构由5.5版本升级到5.6方案
查看>>
大数据时代的遨游
查看>>
从Windows 8.1光盘安装.NET Framework 3.5.1
查看>>
Create Oracle VM High Availability (HA)
查看>>
Memcache持久性分布式数据MemcacheDB
查看>>
联想计算机Lenovo ThinkCentre M910t-NO76的重装
查看>>
大话nbu四(nbu备份恢复catalog)
查看>>