zoukankan      html  css  js  c++  java
  • React事件处理

    React事件处理

    在之前的博文中,我们知道怎么给react的class组件的 dom绑定事件了,现在我们在一起实现给react DOM绑定事件

    给函数组件绑定事件

    function FnEvent(){
    	function handleClick(e){
    		console.log('this is handle FnEvent')
    	}
    	return (
    		<button onClick={handleClick}>FnEvent</button>
    	)
    }
    ReactDOM.render(<FnEvent />,document.getElementById('function-event'))
    

    给class组件绑定事件

    class ButtonEvent extends React.Component{
    	constructor(){
    		super()
    		this.handleClick = this.handleClick.bind(this)
    	}
    //	componentDidMount(){
    //		console.log(this)
    //	}
    	render(){
    		return (
    			<button onClick={this.handleClick}>classEvent</button>
    		)
    	}
    	handleClick(){
    		console.log(this)
    	}
    }
    ReactDOM.render(<ButtonEvent />,document.getElementById('class-event'))
    

    通过上面的代码实现,我们可以发现当我们没有给事件函数绑定组件的this上下文的时候,是访问this的时候,是
    undefined,因此就有了以下问题

    • 为什么给react DOM绑定事件函数,事件函数为什么访问不到组件this?

    react class组件访问this

    当我们用class创建一个类的时候,实例化对象后调用其静态或者原型方法的时候,如果该对象没有this
    值(或this作为布尔,字符串,数字,未定义或null),那么this值在被调用的函数内部将为undefined
    不会发生自动包装。

    class Animal{
    	speak(){
    		return this
    	}
    	static eat(){
    		return this
    	}
    }
    let animal1 = new Animal();
    console.log(animal1.speak());//Animal {}
    let speck = animal1.speak
    console.log(speck())//undeifined
    console.log(Animal.eat());
    /*
     	class Animal{
    		speak(){
    			return this
    		}
    		static eat(){
    			return this
    		}
    	}
     */
    let eat = Animal.eat;
    console.log(eat());//undefined
    

    在上述代码中,在类里面声明了一个handleClick函数,然后给按钮绑定事件的时候相当于隐式的将这个函数赋值给
    onClick的回调函数callback,这样的话handClick就失去了上下文,就访问不到this

    解决访问不到this的方法

    • 在constructor里面使用bindthis.handleClick = this.handleClick.bind(this)
    • <button onClick={this.handleClick.bind(this)}></button>
    • 箭头函数<button onClick={(e) => this.handleClick(e)}></button>

    原生事件和react事件

    例子1

    class EventPrinciple extends React.Component{
    	innerClick = e =>{
    		console.log('A: react inner click');
    	};
    	outerClick = () =>{
    		console.log("B: react outer click")
    	};
    	componentDidMount(){
    		document.getElementById('outer').addEventListener('click',()=>console.log('C:native outer click'));
    		window.addEventListener('click',()=>
    			console.log("D:native window click")
    		)
    	}
    	render(){
    		return(
    			<div id='outer' onClick={this.outerClick}>
    				<button id='inner' onClick={this.innerClick}>BUTTON</button>
    			</div>
    		)
    	}
    }
    ReactDOM.render(<EventPrinciple />,document.getElementById('event-principle'));
    

    上面的代码中,我们在react组件挂载后给'outer'绑定了原生事件,同时绑定了react事件,给window绑定了原生事件,给'inner'
    绑定了react事件,当把react渲染到页面中的时候执行结果如下所示:

    由上面的结果,我们可以看出,react事件和原生事件是有区别的

    并且我们可以知道React时间和原生事件的执行顺序,由此,我们可以理解:

    • react的所有事件都挂载在document中
    • 当真是dom触发后冒泡到document后才会对react事件进行处理
    • 然后执行react合成事件
    • 最后执行真正在document上挂载的事件

    innerClick中的e.stopPropagation()加上,输出的结果如下

    例子二

    class EventPriciple1 extends React.Component{
    	constructor(props){
    		super(props);
    		this.state = {
    			editable:false
    		}
    	}
    	handleClick = () => {
    		console.log('edit button click!!!');
    		this.setState({
    			editable:true
    		})
    	};
    	handleSubmit = e => {
    		console.log('submit event!!');
    		e.preventDefault();//避免页面刷新
    	};
    	render(){
    		return (
    			<form onSubmit={this.handleSubmit}>
    				{this.state.editable?(<button type="submit">submit</button>):(
    					<button type="button" onClick={this.handleClick}>edit</button>
    				)}
    			</form>
    		)
    	}
    }
    ReactDOM.render(<EventPriciple1 />,document.getElementById('event-principle1'))
    

    这段代码中,我们给from绑定了一个react事件,在editable为true给按钮(type为button)绑定react事件handleClick
    点击type为submit的按钮结果如下

    edit button click
    submit event
    

    点击type为button的按钮结果如下

    submit event
    

    从上面两个例子中,我们产生以下两个疑问

    • react事件和原生事件有什么区别
    • 为什么react需要自己实现一个事件系统
    • react事件的事件机制

    js事件

    DOM事件流

    时间流包括三个阶段,简而言之:时间一开始从文档的根节点流向目标对象(捕获阶段),
    然后在目标对象上被触发(目标阶段),之后在回溯到文档的根节点(冒泡阶段)。

    DOM0级处事件处理程序

    <input type="button" value="Click me" id="btn">
    <script>
    	var btn = document.getElementById('btn');
    	btn.onclick = function(){
    		console.log(this.id)
    	}
    </script>
    

    这里是将一个函数赋值给一个事件处理程序的属性,以这种方式添加的时间处理程序会在
    时间流的冒泡阶段被处理。要删除事件将btn.onclick = null即可

    DOM2级事件处理程序

    DOM2级事件定义了addEventListener()removeEventListener()
    两个方法,用于处理和删除事件处理程序的操作

    所有DOM节点都包含这两个方法,它们接受3个参数:要处理的事件名、作为事件
    处理程序的函数和一个布尔值。最后的布尔值参数是true表示在捕获阶段调用事件处理程序,
    如果是false(默认)表示在冒泡阶段调用事件处理程序

    <input type='button' value='Click me' id='btn' />
    <script>
    	var btn = document.getElementById('btn');
    	btn.addEventListener('click',function(){
    		console.log(this.id)
    	},false)
    	btn.addEventListener('click',function(){
    		console.log('hello word')
    	},false)
    	
    </script>
    

    上面代码两个事件处理程序会按照他们的添加顺序触发,但是如果用的是DOM0
    级绑定的事件处理程序,后面的将会覆盖前面的

    通过 addEventListener添加的时间处理程序只能使用removeEventListener
    来移除,移除时候传入参数与添加时候的参数相同,即使匿名函数无法被移除

    <input type='button' value='Click me' id='btn' />
    <scirpt>
    	var btn = document.getElementById('btn');
    	var handler = function(){
    		console.log(this.id);
    	}
    	btn.addEventListener('click',handler,false);
    	btn.removeEventListener('click',handler,false);
    </script>
    

    IE事件处理程序

    IE通常都是特立独行的,它添加和删除事件处理程序的方法分别是
    attachEventdetachEvent

    同样接受事件处理程序名称与事件处理程序函数两个参数,但跟addEventListener
    的区别是:

    • 事件名称需要添加'on',比如'onclik'
    • 没了第三个布尔值,IE8及更早的版本只支持事件冒泡
    • 依然可以添加多个处理程序,但触发顺序是反着来的

    还有一点需要注意,DOM0和DOM2级的方法,其作用域都是在其所依附的
    元素中,attachEvent则是全局,即如果像之前一样使用this.id
    访问到的就不是button元素,而是window,就得不到正确的结果

    react事件和原生事件有什么区别?

    • React时间使用驼峰命名,而不是全部小写
    • 通过JSX,你传递一个而函数作为事件处理程序,而不是一个字符串

    HTML

    <button onclick='handleClick'>BUTTON</button>
    

    React

    <button onClick={handleClick}>BUTTON</button>
    

    另一个区别是,在React中你不能通过返回false来阻止默认行为。必须明确调用preventDefault

    react事件和原生事件可以混用吗?

    react事件和原生事件最好不要混用。原生事件中如果执行了stopPropagation方法,
    则会导致其他react事件失效。因为所有元素的事件将无法冒泡到document上。由此,react事件都将无法被
    注册。

    由上面的例子,我们可以看出React自己实现了一套时间机制,自己模拟了时间冒泡和捕获的过程,采用了事件
    代理,批量更新的方法,并且抹平了各个浏览器的兼容性的问题。

    react事件的事件机制

    react事件机制

  • 相关阅读:
    经典分水岭算法的 C++ 实现
    一个简易的键盘按键测试程序
    工程优化方法中的“最速下降法”和“DFP拟牛顿法”的 C 语言实现
    基于哈夫曼编码的压缩解压程序(C 语言)
    博客选择:博客园 or CSDN
    Spring总结
    CSS总结
    EL表达式总结
    Jdbc总结
    hibernate总结
  • 原文地址:https://www.cnblogs.com/dehenliu/p/12656001.html
Copyright © 2011-2022 走看看