IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React学习三(React的事件处理) -> 正文阅读

[JavaScript知识库]React学习三(React的事件处理)


一、React事件处理

??????React元素的事件处理和DOM元素的很相似,但是有一点语法上的不同:
①在React中事件的命名采用驼峰命名法,而不是原生dom中的小写,如:onclick要写成onClick,onchange要写成onChange。
②响应事件的函数要以对象的形式赋值,而不是以dom字符串的形式。

//DOM方式
<button onclick="clickMe()">请点击</button>
//React方式
<button onClick={clickButton}>请点击</button>
//clickButton是一个函数

**注:**React中的事件是合成事件,并不是dom的原生事件,在dom中可以通过返回false来阻止事件的默认行为,但在react中必须显式的调用事件对象e.preventDefault来阻止事件的默认行为,除了这些点外和原生dom事件并无区别。

二、React中的事件处理函数

??????在React中事件处理函数主要有三种写法,不同的写法解决this指向问题的方式也不同,性能也有差异。

1、使用ES6的箭头函数

(1)在render中使用箭头函数

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <title>事件处理函数-->在render中使用箭头函数</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')
        //创建一个类组件
        class MyComponent extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    msg:'西安邮电大学'
                }
            }
            render(){
                return (
                    <div>
                        <button onClick={()=>{console.log(this.state.msg);}}>点击</button>    
                    </div>
                )
            }
        }
        //进行渲染
        ReactDOM.render(<MyComponent/>,root);
    </script>
</body>
</html>

在这里插入图片描述
??????此时this指向的是当前组件的实例,此方法的优点是不用在构造函数中绑定this,不足是当组件的逻辑比较复杂时,把组件的逻辑写在{}内会导致render函数变得臃肿,不能比较直观的看出ui的结果,代码的可读性也不是很好。

(2)使用class fields语法

??????将箭头函数赋给类的属性,优点:不用在构造函数中绑定this,在render函数中调用简单。

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')
        //创建一个类组件
        class MyComponent extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    msg:'西安邮电大学'
                }
            }
            handClick = ()=> {
                console.log(this.state.msg);
            }
            render(){
                return (
                    <div>
                        <button onClick={ this.handClick }>点击</button>    
                    </div>
                )
            }
        }
        //进行渲染
        ReactDOM.render(<MyComponent/>,root);
    </script>
</body>
...

在这里插入图片描述

2、在constructor函数中bind

??????将事件处理函数作为类的成员函数。

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')
        //创建一个类组件
        class MyComponent extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    msg:'西安邮电大学',
                    number:0
                }
                this.add = this.add.bind(this)
            }
            add(){
                let num = this.state.number;
                num++;
                this.setState({
                    number:num
                })
                console.log(this.state.number);
            }
            render(){
                return (
                    <div>
                        <button onClick={ this.add }>Number++</button>    
                    </div>
                )
            }
        }
        //进行渲染
        ReactDOM.render(<MyComponent/>,root);
    </script>
</body>
...

在这里插入图片描述
注意:
①在定义事件处理函数时,是无法识别this(即this是undefined的),必须在构造函数中绑定this
②这种方法的好处是每次渲染都不会重新创建一个回调函数,没有额外的性能损失,但是如果在一个组件中有很多的事件函数时,这种在构造函数中绑定this的方法会显得繁琐。

3、在render函数中使用bind

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')
        //创建一个类组件
        class MyComponent extends React.Component{
            constructor(props){
                super(props);
                this.state = {
                    msg:'西安邮电大学',
                    number:0
                }
            }
            add(){
                let num = this.state.number;
                num++;
                this.setState({
                    number:num
                })
                console.log(this.state.number);
            }
            render(){
                return (
                    <div>
                        <button onClick={ this.add.bind(this) }>Number++</button>    
                    </div>
                )
            }
        }
        //进行渲染
        ReactDOM.render(<MyComponent/>,root);
    </script>
</body>
...

在这里插入图片描述

注意:此方法在每次render时都会重新创建一个新的函数,性能有一定的损失,但在事件处理函数需要传参时,效果比较好。

4、注意

(1)React事件的命名采用小驼峰式,而不是纯小写,且事件名称后不能加(),否则会直接执行。
(2)不能通过返回false的方式组织默认行为,必须显式调用preventDefalut。
(3)必须谨慎对待JSX回调函数中的this,在JavaScript中,class(类)的方法默认不会绑定this。如果忘记绑定this.textChange并把它传入了onChange,当调用这个函数的时候this的值为undefined。如果觉得bind麻烦,还可以使用箭头函数。

三、事件处理中传参

??????在开发当中,经常遇到对一个列表做操作,可能包含删除、修改、查看。这时绑定事件就需要传参,通常为id。传参的方式有两种。

1、直接传递参数

①在构造函数中给事件处理函数绑定this,调用事件处理函数时直接传参;
??????注:在箭头函数中调用事件处理函数时不需要绑定this。
②在render函数中调用事件处理函数时进行this的绑定。

...
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件处理中的参数传递</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root');
        //1.定义类组件
        class Clock extends React.Component{
            constructor(props){
                super(props)
                this.state= {
                    list:[
                        {
                            id: 111,
                            msg: '西安邮电大学'
                        },
                        {
                            id: 222,
                            msg: '西安理工大学'
                        },
                        {
                            id: 333,
                            msg: '西安科技大学'
                        }
                    ],
                }
                this.handleClick = this.handleClick.bind(this)//在render函数调用事件处理函数时使用
            }
            handleClick(id){ //事件处理函数
                console.log('编号:'+id);
            }
            render(){
                //获取状态属性值
                const { list } = this.state 
                return (
                    <div>
                        {
                            list.map((item)=>
                               //<button onClick={ ()=>{this.handleClick(item.id)}} key={item.id}>{ item.msg }</button> //在箭头函数中调用事件处理函数时不需要绑定this。
                               <button onClick={ this.handleClick.bind(this,item.id) } key={item.id}>{ item.msg }</button>//在render函数中调用事件处理函数时进行this的绑定
                            )
                        }
                    </div>
                )
            }
        }
        //2.渲染
        ReactDOM.render(<Clock/>,root)
    </script>
</body>
</html>
...

在这里插入图片描述

2、使用data属性

??????在定义UI控件时使用data自定义属性,在事件处理函数中使用"e.target.dataset.属性名"来获取属性值。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件处理中的参数传递</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root');

        //1.定义类组件
        class Clock extends React.Component{
            constructor(props){
                super(props)
                this.state= {
                    list:[
                        {
                            id: 111,
                            msg: '西安邮电大学'
                        },
                        {
                            id: 222,
                            msg: '西安理工大学'
                        },
                        {
                            id: 333,
                            msg: '西安科技大学'
                        }
                    ],
                    msg: '编号:'
                }
                this.handleClick = this.handleClick.bind(this)
            }
            handleClick(e){ //事件处理函数,e表示触发事件的对象
                let str = this.state.msg
                console.log(str + e.target.dataset.count)
            }
            render(){
                //获取状态属性值
                const { list } = this.state 
                return (
                    <div>
                        {
                            list.map((item)=>
                                  <button 
                                     onClick={ this.handleClick.bind(this) } 
                                     key={item.id}
                                     data-count = { item.id}  //标签的自定义属性用'data-'开头后跟自定义属性名
                                    >{ item.msg }</button>
                            )
                        }
                    </div>
                )
            }
        }
        //2.渲染
        ReactDOM.render(<Clock/>,root)
    </script>
</body>
</html>

在这里插入图片描述

四、事件流

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件流</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')

        //1.定义CSS样式
        const style = {
            child: {
                width: '100px',
                height: '100px',
                backgroundColor: 'red'
            },
            parent: {
                width: '150px',
                height: '150px',
                backgroundColor: 'blue'
            },
            ancestor: {
                width: '200px',
                height: '200px',
                backgroundColor: 'green'
            }
        }

        //2.定义类组件
        class App extends React.Component{
            render(){
                return (
                    <div
                        onClick= { ()=>{ console.log('ancestor')}}
                        style = { style.ancestor }
                    >
                        <div
                           onClick={ ()=>{ console.log('parent')}}
                           style = { style.parent }
                        >
                            <div 
                               onClick={ ()=>{ console.log('child')}}
                               style = {style.child }
                            >
                            </div>
                        </div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App/>,root)
    </script>
</body>
</html>

在这里插入图片描述

??????在该实例中,3个div嵌套显示,并且每个元素上均绑定onClick事件。
??????当用户点击红色区域时,可以看到控制台先后打印出child->parent->ancestor,这是因为在React的事件处理系统中,默认的事件流就是冒泡
??????注意:如果我们希望以捕获的方式来触发事件的话,可以使用onClickCapture来绑定事件,也就是在事件类型后面加一个后缀Capture。这样,当点击红色区域div,就可以看到事件流是从ancestor->parent->child传播了。

...
                    <div
                        onClickCapture= { ()=>{ console.log('ancestor')}}
                        style = { style.ancestor }
                    >
                        <div
                           onClickCapture={ ()=>{ console.log('parent')}}
                           style = { style.parent }
                        >
                            <div 
                               onClickCapture={ ()=>{ console.log('child')}}
                               style = {style.child }
                            >
                            </div>
                        </div>
                    </div>
...

在这里插入图片描述

五、事件委托

??????在合成事件系统中,所有的事件都是绑定在document元素上,即,虽然我们在某个react元素上绑定了事件,但是,最后事件都委托给document统一触发。
??????在合成事件中只能组织合成事件中的事件传播。
??????还是上述例子,我们给红色div的onClick事件,添加stopPropagation()方法来组织冒泡,此时点击红色div,控制台上只输出了child,说明此时已成功阻止了冒泡。

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')

        //1.定义CSS样式
        const style = {
            child: {
                width: '100px',
                height: '100px',
                backgroundColor: 'red'
            },
            parent: {
                width: '150px',
                height: '150px',
                backgroundColor: 'blue'
            },
            ancestor: {
                width: '200px',
                height: '200px',
                backgroundColor: 'green'
            }
        }

        //2.定义类组件
        class App extends React.Component{
            render(){
                return (
                    <div
                        onClick = { ()=>{ console.log('ancestor')}}
                        style = { style.ancestor }
                    >
                        <div
                           onClick ={ ()=>{ console.log('parent')}}
                           style = { style.parent }
                        >
                            <div 
                               onClick ={ (e)=>{ 
                                   console.log('child')
                                   e.stopPropagation()//组织冒泡
                                }}
                                style = {style.child }
                            >
                            </div>
                        </div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App/>,root)
    </script>
</body>
...

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

六、事件对象

??????在合成事件(SyntheticEvent)中,依然可以获取到事件发生时的event对象。
??????我们给div元素绑定了一个click事件,在用户点击时,在控制台输出event对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件对象</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')

        //1.定义样式规则
        const style = {
            "mydiv": {
                width: '150px',
                height: '150px',
                backgroundColor: 'red'
            }
        }
        //2.定义类组件
        class App extends React.Component{
            constructor(props){
                super(props)
                this.state = {
                    x: 0,
                    y: 0
                }
            }
            render(){
                return (
                    <div>
                        <div style = { style['mydiv']}  //以数组的方式设置样式
                            onClick = {(e)=>{
                                console.log(e);
                            }}
                        >
                          X: {this.state.x},Y: { this.state.y }
                        </div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App />,root)
    </script>
</body>
</html>

在这里插入图片描述

(1)扩展

??????将用户点击时的坐标在div元素中显示出来,可以通过clientX和clientY来访问。

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')

        //1.定义样式规则
        const style = {
            "mydiv": {
                width: '150px',
                height: '150px',
                backgroundColor: 'red'
            }
        }
        //2.定义类组件
        class App extends React.Component{
            constructor(props){
                super(props)
                this.state = {
                    x: 0,
                    y: 0
                }
            }
            render(){
                return (
                    <div>
                        <div style = { style['mydiv']}  //以数组的方式设置样式
                             onClick= { (event)=> { //'event'对象不是原生的event,但是可以通过event来获取原生的事件对象的部分属性
                                 this.setState({
                                     x: event.clientX,
                                     y: event.clientY
                                 })
                                 console.log(event)
                             }}
                        >
                          X: {this.state.x},Y: { this.state.y }
                        </div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App />,root)
    </script>
</body>
...

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

(2)在异步操作中获取event

问题:当事件触发、响应结束后,event对象会被清空,但是异步数据还没有得到,在得到异步数据之后再去访问event对象的属性就会报错。
解决办法:先将event对象的某些属性值保存起来,得到异步数据之后再来使用这些属性值。

...
<body>
    <div id="root"></div>
    <script type="text/babel">
        let root = document.getElementById('root')

        //1.定义样式规则
        const style = {
            "mydiv": {
                width: '150px',
                height: '150px',
                backgroundColor: 'red'
            }
        }

        //2.定义类组件
        class App extends React.Component{
            constructor(props){
                super(props)
                this.state = {
                    x: 0,
                    y: 0
                }
            }
            render(){
                return (
                    <div>
                        <div style = { style['mydiv']}  //以数组的方式设置样式
                             onClick= { (event)=> { //'event'对象不是原生的event,但是可以通过event来获取原生的事件对象的部分属性
                                const { clientX,clientY } = event
                                setTimeout(()=>{
                                    this.setState({
                                        x: clientX,
                                        y: clientY
                                    })
                                },1000)
                             }}
                        >
                          X: {this.state.x},Y: { this.state.y }
                        </div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App />,root)
    </script>
</body>
...

在这里插入图片描述

(3)原生事件和合成事件的混合使用

**示例:**我们提供一个按钮和一个div元素,当用户点击按钮时,显示div,当点击页面其他区域时,则隐藏。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原生事件和合成事件的混合使用</title>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
</head>
<body>
    <div id="root"></div>
    <script type="text/babel">
        class App extends React.Component{
            constructor(props){
                super(props)
                this.state = {
                    isShow: 'none'
                }
            }
            button = React.createRef()  //创建了一个关联属性button
            componentDidMount(){
                document.addEventListener('click',e=>{  //注册原生事件
                    /*
                        e.target表示触发click事件的对象
                        this.button.current表示当前的按钮
                    */
                    if(e.target != this.button.current){ 
                        this.setState({
                            isShow: 'none'
                        })
                    }
                })
            }
            render(){
                return (
                    <div>
                        <button
                          ref={ this.button }
                          onClick={ ()=> { //合成事件
                            this.setState({
                                  isShow: 'block'
                              })
                            } }
                        >
                        点击显示
                        </button>
                        <br/> <br/>
                        <div style={{
                            display: this.state.isShow,
                            width: '100px',
                            height: '100px',
                            backgroundColor: 'red'
                        }}></div>
                    </div>
                )
            }
        }
        //3.渲染
        ReactDOM.render(<App/>,root)
    </script>
</body>
</html>

在这里插入图片描述

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-15 22:23:40  更:2022-03-15 22:23:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:16:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码