zoukankan      html  css  js  c++  java
  • 原理篇:事件系统

    React为什么要实现一套自己的事件系统?

    A:为了兼容各浏览器对事件处理的差异性/

    冒泡和捕获

    1. 冒泡:事件从最内层的元素开始,一直向上传播,直到document对象。
    2. 捕获:事件从最外层开始,直到最具体的元素。
    3. addEventListener(event, function,useCapture):useCapture=true,事件捕获阶段调用处理函数;useCapture=false,事件冒泡阶段调用处理函数;

    react 中, 想要在捕获阶段执行可以将事件后面加上 Capture 后缀。

    <div>
        <button onClick={handleClick} onClickCapture={ handleClickCapture }  >点击</button>
    </div>
    
    1. 阻止冒泡:e.stopPropagation();
    2. 阻止默认行为

      原生事件: e.preventDefault() 和 return false ;

      react事件:e.preventDefault()

      在react中给元素绑定的事件并不是真正的事件处理函数,所以无法使用return false 阻止默认行为。

    React如何模拟阻止事件冒泡

    function runEventsInBatch(){
        const dispatchListeners = event._dispatchListeners;
        if (Array.isArray(dispatchListeners)) {
        for (let i = 0; i < dispatchListeners.length; i++) {
          if (event.isPropagationStopped()) { /* 判断是否已经阻止事件冒泡 */
            break;
          }    
          dispatchListeners[i](event) /* 执行真正的处理函数 及handleClick1... */
        }
      }
    }
    

    事件合成

    1. React的事件不是绑定在元素上,而是统一绑定在顶部的容器上。
    2. 元素绑定的事件不是原生事件,而是react合成事件。比如onClick绑定的是click事件,onChange事件又blur ,change ,focus等多个事件组成。

    绑定在document上的事件处理函数,是上面所写的handleClick吗?

    A:绑定在 document 的事件,是由react中的dispatchEvent统一处理。只要是 React 事件触发,首先执行的就是 dispatchEvent 。

    const listener = dispatchEvent.bind(null,'click',eventSystemFlags,document) 
    /* TODO: 重要, 这里进行真正的事件绑定。*/
    document.addEventListener('click',listener,false) 
    

    事件触发流程

    下面代码触发顺序是怎样的?

    export default function Index(){
        const handleClick1 = () => console.log(1)
        const handleClick2 = () => console.log(2)
        const handleClick3 = () => console.log(3)
        const handleClick4 = () => console.log(4)
        return <div onClick={ handleClick3 }  onClickCapture={ handleClick4 }  >
            <button onClick={ handleClick1 }  onClickCapture={ handleClick2 }  >点击</button>
        </div>
    }
    
    1. dispatchEvent 执行会传入真实的事件源 button 元素本身,接下来就是批量更新。
    export function batchedEventUpdates(fn,a){
        isBatchingEventUpdates = true; //打开批量更新开关
        try{
           fn(a)  // 事件在这里执行
        }finally{
            isBatchingEventUpdates = false //关闭批量更新开关
        }
    }
    
    1. 通过 onClick 找到对应的处理插件 SimpleEventPlugin ,合成新的事件源 e 。
    2. 形成事件执行队列:

      3.1 如果遇到捕获阶段事件 onClickCapture ,就会 unshift 放在数组前面。以此模拟事件捕获阶段。

      3.2 如果遇到冒泡阶段事件 onClick ,就会 push 到数组后面,模拟事件冒泡阶段。

      3.3 一直收集到最顶端 app ,形成执行队列。
    3. 依次执行队列的函数。

    如上点击一次按钮,4个事件执行顺序是这样的:

    • 第一次事件源查找在button上。
    • handleClick1冒泡事件push处理,handleClick2捕获事件unshift处理。形成结构 [ handleClick2 , handleClick1 ]。
    • 接着向上查找事件源,遇到div。
    • handleClick3 冒泡事件 push 处理,handleClick4 捕获事件 unshift 处理。[handleClick4, handleClick2 , handleClick1, handleClick3 ]
    • 依次执行数组里面的事件,所以打印 4 2 1 3。
  • 相关阅读:
    448-查找数组中消失的所有数字
    977 -排序数组的正方形
    爬虫小总结
    增量式爬虫
    分布式爬虫
    CrawlSpider:类,Spider的一个子类
    中间件
    中间件
    scrapy图片数据爬取之ImagesPipeline
    scrapy五大核心组件
  • 原文地址:https://www.cnblogs.com/renzhiwei2017/p/15761307.html
Copyright © 2011-2022 走看看