‌React事件系统深度剖析‌

‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌React 事件系统深度剖析

在现代 Web 开发中,React 提供了一套完整、统一的事件系统,使得开发者可以用相同的方式处理浏览器的原生事件,无需担心不同浏览器间的兼容性问题。本文将从 合成事件(Synthetic Event)事件委托(Event Delegation)事件池(Event Pooling)事件传播(Propagation)Hook 中的事件使用 等多个方面,进行系统性的深度剖析,并辅以代码示例与 ASCII 图解帮助你快速理解 React 事件系统的核心原理和实战要点。


一、概述:为什么需要 React 的事件系统

  1. 跨浏览器兼容
    不同浏览器的原生事件存在细节差异,例如事件对象属性、事件名称(click vs onclick)等。React 将各种浏览器的原生事件封装为统一接口,开发者只需记住一套 API 就能适配所有主流浏览器。
  2. 性能优化:事件委托
    在传统 DOM 操作中,为每个元素单独绑定事件,会随着元素数量增多而带来更多内存和性能开销。React 通过事件委托机制,在顶层统一监听事件,然后再根据触发元素分发,让事件绑定更加高效。
  3. 一致性和可控性
    React 的合成事件模拟了 W3C 标准的事件行为,规范了事件对象的属性和方法(如 event.preventDefault()event.stopPropagation() 等),简化了处理逻辑。同时,React 在批量更新时对事件进行了“批量合并”与“延迟触发”,保证了状态更新的一致性。

下面将从事件对象本身、委托机制、生命周期到实战用例,为你逐步揭开 React 事件系统的面纱。


二、合成事件(Synthetic Event)

2.1 合成事件的定义与作用

React 并不直接将浏览器原生的 MouseEventKeyboardEventTouchEvent 等暴露给组件,而是对它们进行“包装”,形成一个统一的 SyntheticEvent 对象。它具有以下特点:

  • 跨浏览器一致性
    SyntheticEvent 将各浏览器的不同实现内聚到一个共用接口,开发者无需关心 event.targetevent.keyCode 等在不同浏览器中的表现差异。
  • 性能优化:事件池
    默认情况下,React 会回收 SyntheticEvent 对象以减少内存分配。当事件回调执行完毕后,事件对象的内部属性会被重置,事件对象本身会被放入事件池重新利用。
  • 附加便利方法
    React 会在 SyntheticEvent 上附加一些便捷的方法或属性,例如:

    • event.nativeEvent:对应浏览器原生事件对象。
    • event.persist():取消事件池回收,保留完整事件对象,常用于异步处理。

在 React 组件中,我们通常通过 onClick={handleClick}onChange={handleChange}onKeyDown={handleKeyDown} 等方式接收 SyntheticEvent

2.2 代码示例:基本合成事件用法

import React from 'react';

function App() {
  const handleClick = (event) => {
    // event 是一个 SyntheticEvent 实例
    console.log('事件类型:', event.type); // 通常返回 'click'
    console.log('触发元素:', event.target); // 真实的 DOM 元素
    console.log('原生事件:', event.nativeEvent); // 浏览器原生事件对象

    // 示例:阻止默认行为(若是<a>标签等)
    event.preventDefault();

    // 示例:停止事件传播
    event.stopPropagation();
  };

  return (
    <div>
      <button onClick={handleClick}>点击我</button>
    </div>
  );
}

export default App;

2.2.1 event.preventDefault()event.stopPropagation()

  • preventDefault()
    阻止事件的默认行为,例如 <a> 标签的跳转、表单的提交等。
  • stopPropagation()
    阻止事件向上冒泡或向下捕获,只有当前节点的事件处理器会被执行。

2.3 事件池(Event Pooling)

出于性能考虑,React 在事件回调执行完毕后,会将合成事件对象放回“事件池”中,用于后续的重新分配。事件池机制意味着在事件处理函数执行完毕后,事件对象的属性就可能会被重置:

import React from 'react';

function App() {
  const handleClick = (event) => {
    console.log(event.type); // 正常输出 'click'
    
    setTimeout(() => {
      console.log(event.type); 
      // 可能输出 null 或者抛出 “Cannot read property 'type' of null”
      // 因为事件对象已被回收
    }, 100);

    // 如果想在异步中使用事件,必须先调用 event.persist()
    event.persist(); 
    setTimeout(() => {
      console.log(event.type); // 依然是 'click'
    }, 100);
  };

  return <button onClick={handleClick}>点击我</button>;
}
  • event.persist()
    调用之后,React 不再回收该事件对象,允许我们在异步函数中继续读取其属性。缺点是会导致对象无法复用,增加内存开销,所以应谨慎使用,仅在确实需要异步访问事件对象时才调用。

2.4 合成事件的常见类型

React 支持大多数浏览器常见的事件类型,常见分组如下:

  • 鼠标事件(Mouse Events)
    onClick, onDoubleClick, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, onMouseMove, …
  • 键盘事件(Keyboard Events)
    onKeyDown, onKeyUp, onKeyPress
  • 表单事件(Form Events)
    onChange, onInput, onSubmit, onFocus, onBlur
  • 触摸事件(Mobile Touch Events)
    onTouchStart, onTouchMove, onTouchEnd, onTouchCancel
  • 指针事件(Pointer Events)
    onPointerDown, onPointerMove, onPointerUp, onPointerCancel
  • 拖放事件(Drag Events)
    onDrag, onDragStart, onDragEnd, onDrop
  • 焦点事件(Focus Events)
    onFocus, onBlur
  • 其他事件
    onScroll, onWheel, onContextMenu, onError, onLoad, …

通常我们只需关注其中常用的几种,根据业务场景灵活选择。


三、事件委托与事件分发机制

3.1 传统 DOM 中的事件绑定 vs React 中的事件委托

传统 DOM操作中,开发者往往在需要的 DOM 元素上直接绑定事件处理器,例如:

const btns = document.querySelectorAll('button');
btns.forEach((btn) => {
  btn.addEventListener('click', () => {
    console.log('按钮被点击');
  });
});

当页面中有成百上千个可点击元素时,需要逐个绑定回调,既影响性能,又难以维护。‍

React 为了统一和优化,采用了一种“事件委托”的方式:

  1. React 会在最顶层的根 DOM 节点(通常是 document 或者 root 容器)上,仅添加一套事件监听器。
  2. 当子节点发生事件(如 click)时,浏览器会先触发捕获阶段、自身阶段,再到冒泡阶段。在冒泡到根节点时,React 拦截并获取原生事件。
  3. React 通过 event.target(或 event.currentTarget)来确定具体触发事件的子元素,然后在对应的组件上触发相应的回调。

这样,只需要一套顶层监听,大大减少了事件绑定数量,实现了“统一分发”。

3.1.1 事件委托示意 ASCII 图

┌─────────────────────────────────────────────────────────────┐
│                     React 根容器 (root)                     │
│  ┌-------------------------------------------------------┐  │
│  │         document.addEventListener('click', ...)      │  │
│  └-------------------------------------------------------┘  │
│           ▲                  ▲                 ▲          │
│           │                  │                 │          │
│      冒泡阶段             冒泡阶段           冒泡阶段       │
│           │                  │                 │          │
│  ┌────────┴───────┐  ┌───────┴────────┐  ┌─────┴────────┐   │
│  │        组件A     │  │     组件B        │  │    组件C       │   │
│  │   <button>     │  │   <input>       │  │  <div>        │   │
│  └────────┬───────┘  └───────┬────────┘  └─────┬────────┘   │
│           │                  │                 │          │
│        用户点击            用户点击           用户点击      │
│           ▼                  ▼                 ▼          │
│   浏览器触发原生 click     浏览器触发原生 click    浏览器触发原生 click │
└─────────────────────────────────────────────────────────────┘
  1. 用户在某个子组件上触发原生 click
  2. 事件一路向上冒泡到根容器,由根容器上唯一的 click 监听器捕获并转交给 React。
  3. React 根据冒泡链,找到触发事件的子组件实例,将合成事件分发给对应的 props.onClick 回调。

3.2 React 内部的事件分发流程

  1. 注册阶段
    当 React 元素渲染时,如果 JSX 中存在 onClick={...} 等事件属性,React 在内部记录下该组件对应的事件类型和回调函数。并确保在最顶层绑定了相应的原生事件监听器(如 document.addEventListener('click', dispatchEvent))。
  2. 捕获与分发阶段

    • 浏览器原生事件触发后,冒泡到根节点,React 的顶层监听器收到原生事件,创建一个对应的 SyntheticEvent
    • React 会根据事件触发时的 event.target(真实 DOM 节点)在其虚拟 DOM 树(fiberNode)中找到对应的组件实例。
    • 按照 React 自身的“事件冒泡/捕获”顺序(通常只支持冒泡),依次执行从目标组件到根组件路径上注册的回调。
  3. 清理阶段

    • 当事件处理结束后,React 可能会将 SyntheticEvent 放入事件池,或者在批量更新阶段进行状态更新并重新渲染组件树。

四、深入事件传播:冒泡、捕获与阻止传播

4.1 捕获阶段(Capture Phase)与冒泡阶段(Bubble Phase)

尽管 React 只支持“冒泡”阶段的事件绑定,但在底层实现中也对事件捕获阶段做了简单处理。标准的事件传播分为三个阶段:

  1. 捕获阶段(Capture)
    事件从根节点沿层级向下传播到目标节点,但 React 默认不监听捕获阶段。
  2. 目标阶段(Target)
    事件抵达触发元素本身,React 在此阶段会执行目标元素上注册的回调。
  3. 冒泡阶段(Bubble)
    事件从目标元素沿层级向上传播到根节点,React 会在此阶段执行沿途父组件上注册的回调。

在 React 中,若要监听“捕获”阶段的事件,可以使用 onClickCaptureonMouseDownCapture 等以 Capture 结尾的属性。例如:

<div onClickCapture={() => console.log('捕获阶段')} onClick={() => console.log('冒泡阶段')}>
  <button>点击我</button>
</div>

当点击 <button> 时,控制台输出:

捕获阶段
冒泡阶段

4.2 event.stopPropagation()event.nativeEvent.stopImmediatePropagation()

  • event.stopPropagation()
    在 React 合成事件中调用,阻止当前事件继续向上传播到父组件的合成事件处理器。
  • event.nativeEvent.stopImmediatePropagation()
    直接作用于原生事件,阻止原生事件的后续监听器执行(包括在 React 之外的监听器)。应谨慎使用,避免与 React 事件系统产生冲突。

4.3 代码示例:事件传播控制

import React from 'react';

function App() {
  const handleParentClick = () => {
    console.log('父组件 click 回调');
  };

  const handleChildClick = (event) => {
    console.log('子组件 click 回调');
    // 阻止冒泡到父组件
    event.stopPropagation();
  };

  return (
    <div onClick={handleParentClick} style={styles.parent}>
      <div onClick={handleChildClick} style={styles.child}>
        点击我(子组件)
      </div>
    </div>
  );
}

const styles = {
  parent: {
    width: '200px',
    height: '200px',
    backgroundColor: '#f0f0f0',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
  child: {
    width: '100px',
    height: '100px',
    backgroundColor: '#87ceeb',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
};

export default App;
  • 点击子组件,控制台只会输出 子组件 click 回调,因为 event.stopPropagation() 阻止了冒泡。
  • 如果去掉 event.stopPropagation(),点击子组件时会先输出 子组件 click 回调,然后输出 父组件 click 回调

五、合成事件与原生事件的区别

5.1 合成事件池的重用机制

React 通过事件池(会复用 SyntheticEvent 对象)来减少对象分配,节省内存。在事件回调执行完毕后,React 会将事件对象内部的所有属性重置为 null,并放回池中。下一次相同类型的事件发生时,React 会重用该对象。

// 伪代码示意:React 内部如何进行事件回收
function handleNativeEvent(nativeEvent) {
  let syntheticEvent = eventPool.length
    ? eventPool.pop()
    : new SyntheticEvent();

  syntheticEvent.initialize(nativeEvent);
  dispatchEventToReactComponents(syntheticEvent);
  // 回收,清空属性
  syntheticEvent.destructor();
  eventPool.push(syntheticEvent);
}

5.2 何时取消池化:event.persist()

如果在异步逻辑中想保留事件对象(例如在 setTimeoutPromise.then 中)访问事件属性,必须先调用 event.persist() 取消池化。否则访问 event.typeevent.target 等属性时,可能会报 null 或者 “已被回收” 的错误。

import React from 'react';

function App() {
  const handleClick = (event) => {
    event.persist(); // 取消事件池化
    setTimeout(() => {
      console.log('事件类型:', event.type); // 依然可以访问
      console.log('触发元素:', event.target);
    }, 100);
  };

  return <button onClick={handleClick}>延迟访问事件</button>;
}

export default App;

六、React Hook 中使用事件注意事项

函数组件Hook 时代,我们常常把事件处理函数写在组件内部,而不是类组件的 this.handleClick。需要注意以下几点:

  1. 事件回调中的闭包问题
    当把事件处理函数定义在组件内部且依赖某些状态时,若没有加上适当的依赖,可能会导致“闭包捕获旧值”问题。例如:

    import React, { useState, useEffect } from 'react';
    
    function Counter() {
      const [count, setCount] = useState(0);
    
      const handleClick = () => {
        // 这个回调捕获了初始的 count 值(0)
        setTimeout(() => {
          alert('当前 count 值为:' + count);
        }, 1000);
      };
    
      return (
        <div>
          <p>count: {count}</p>
          <button onClick={() => setCount(count + 1)}>++</button>
          <button onClick={handleClick}>延迟弹出 count</button>
        </div>
      );
    }

    如果先点击“++”,count 变为 1 后,再点击“延迟弹出 count”,弹窗依然会显示 “0” 而不是最新值 “1”。原因是 handleClick 函数中的 count 被闭包捕获了初始值。

    解决方法

    • handleClick 写成带有最新 count 的回调:

      const handleClick = () => {
        setTimeout(() => {
          // React 每次渲染都会创建新的 handleClick,因此访问到的 count 永远是最新的
          alert('当前 count 值为:' + count);
        }, 1000);
      };
    • 或者使用 useRef 保存最新值:

      const countRef = useRef(count);
      useEffect(() => {
        countRef.current = count;
      }, [count]);
      
      const handleClick = () => {
        setTimeout(() => {
          alert('当前 count 值为:' + countRef.current);
        }, 1000);
      };
  2. useEffect 或回调函数中访问事件对象
    如果在 useEffectPromise.thensetTimeout 等异步逻辑中访问事件对象,必须先 event.persist()。否则事件对象会在回调执行前被回收。

    function App() {
      const handleClick = (event) => {
        event.persist();
        Promise.resolve().then(() => {
          console.log(event.type); // 依然可访问
        });
      };
    
      return <button onClick={handleClick}>点击我</button>;
    }
  3. useCallback 缓存事件回调
    若需要对事件回调进行依赖收集,以减少不必要的重新创建,可以使用 useCallback。例如:

    const handleClick = useCallback((event) => {
      console.log('点击了', event.target);
    }, []); // 空依赖,仅创建一次

    这样在组件多次渲染时,handleClick 引用不会改变,有助于优化子组件 shouldComponentUpdateReact.memo 的判断。


七、事件高级应用场景

7.1 高阶组件中的事件传递与增强

有时我们需要对现有事件进行增强或统一处理,可通过 HOC(高阶组件)包装原组件,实现“事件劫持”或“事件埋点”。示例如下:

import React from 'react';

// HOC:为组件注入点击埋点逻辑
function withClickTracker(WrappedComponent) {
  return function ClickTracker(props) {
    const handleClick = (event) => {
      console.log('[埋点] 点击发生,组件:', WrappedComponent.name, '元素:', event.target);
      // 保证原有 onClick 回调仍然能运行
      props.onClick && props.onClick(event);
    };

    // 重新传递 onClick,覆盖原有
    return <WrappedComponent {...props} onClick={handleClick} />;
  };
}

// 原始按钮组件
function Button(props) {
  return <button {...props}>{props.children}</button>;
}

const TrackedButton = withClickTracker(Button);

function App() {
  return (
    <div>
      <TrackedButton onClick={() => alert('按钮被点击')}>埋点按钮</TrackedButton>
    </div>
  );
}

export default App;
  • withClickTracker 会拦截 WrappedComponentonClick,先做埋点再执行原回调。
  • 通过 HOC 能以最小侵入的方式为点击事件添加统一逻辑(如统计、日志、权限校验等)。

7.2 自定义事件名与事件委托

有时我们需要在容器上统一监听某种“自定义行为”,并动态判断触发元素。例如,实现一个点击容器内任何含 data-action 属性的元素,就触发某逻辑的需求。示例如下:

import React, { useRef, useEffect } from 'react';

function App() {
  const containerRef = useRef(null);

  useEffect(() => {
    const handleClick = (event) => {
      const action = event.target.getAttribute('data-action');
      if (action) {
        console.log('触发自定义行为:', action);
      }
    };

    const container = containerRef.current;
    container.addEventListener('click', handleClick);

    // 清理
    return () => {
      container.removeEventListener('click', handleClick);
    };
  }, []);

  return (
    <div ref={containerRef} style={styles.container}>
      <button data-action="save">保存</button>
      <button data-action="delete">删除</button>
      <button>普通按钮</button>
    </div>
  );
}

const styles = {
  container: {
    border: '1px solid #ccc',
    padding: '20px',
  },
};

export default App;
  • 虽然这里没有使用 React 的合成事件,而是直接在 DOM 上注册原生事件。但思路与 React 的事件委托相似:只在容器上注册一次监听,然后根据 event.target 判断是否触发自定义行为。
  • 在 React 中也可写成 <div onClick={handleClick}>…</div>,由于 React 统一在根节点做了事件委托,性能同样优越。

7.3 处理事件冒泡与嵌套组件

当某些父组件和子组件都需要响应同一个事件时,需要注意以下几点:

// Scenario: 父组件与子组件都监听 onClick
function Parent() {
  const handleParentClick = () => {
    console.log('父组件点击');
  };

  return (
    <div onClick={handleParentClick} style={styles.parent}>
      <Child />
    </div>
  );
}

function Child() {
  const handleChildClick = (event) => {
    console.log('子组件点击');
    // 如果希望同时执行父组件的回调,不要调用 stopPropagation
  };

  return <button onClick={handleChildClick}>点击我</button>;
}
  • 默认情况下,点击子组件时会先输出 子组件点击,然后输出 父组件点击
  • 如果在子组件中调用了 event.stopPropagation(),则会阻止事件继续冒泡到父组件。

八、ASCII 图解:React 事件分发与委托

下面用 ASCII 图示描述 React 在浏览器中的事件分发流程,从 React 组件中的事件绑定到最终的浏览器原生事件捕获,再回传到组件实例并执行回调。

┌────────────────────────────────────────────────────────────────────────┐
│                              浏览器 DOM 树                              │
│  ┌──────────────────────────────────────────────────────────────────┐ │
│  │                            document                               │ │
│  │  ┌────────────────────────────────────────────────────────────┐  │ │
│  │  │                   React 根节点 (root DOM)                     │  │ │
│  │  │  ┌──────────────────────────────────────────────────────┐    │  │ │
│  │  │  │   <div onClick={handleParentClick}>                 │    │  │ │
│  │  │  │  ┌────────────────────────────────────────────────┐  │    │  │ │
│  │  │  │  │ <button onClick={handleChildClick}>            │  │    │  │ │
│  │  │  │  │  “点击我” 文本                                 │  │    │  │ │
│  │  │  │  └────────────────────────────────────────────────┘  │    │  │ │
│  │  │  │                                                      │    │  │ │
│  │  │  └──────────────────────────────────────────────────────┘    │  │ │
│  │  └────────────────────────────────────────────────────────────┘  │ │
│  └──────────────────────────────────────────────────────────────────┘ │
│                                                                        │
│      用户点击 “点击我” 按钮 → 浏览器原生 click 事件触发 → 冒泡到 root 节点   │
│                                                                        │
│      React 在根节点的全局监听器捕获原生事件,创建 SyntheticEvent 对象       │
│                                                                        │
│      React 寻找对应的组件路径:button → div → root → ...                │
│                                                                        │
│      React 在 SyntheticEvent 上先执行 target 阶段(child 对应的回调)       │
│        └─ 执行 handleChildClick                                        │
│                                                                        │
│      若未阻止冒泡(stopPropagation),React 继续在冒泡阶段调用父组件回调      │
│        └─ 执行 handleParentClick                                       │
│                                                                        │
│      完成后,SyntheticEvent 放入事件池,等待下次复用                         │
└────────────────────────────────────────────────────────────────────────┘
  • 从上图可见,React 的 全局顶层监听 + 路径查找 + 合成事件生成,实现了“统一绑定、按需分发”的高效机制。
  • 每次事件都会生成一个新的 SyntheticEvent(从池里取或新创建),执行完毕后被回收。

九、常见问题与最佳实践

  1. 何时使用 event.persist()

    • 当你需要在异步函数中访问事件对象时(如 setTimeoutPromise.thensetImmediate),必须先调用 event.persist()。否则事件对象会在回调执行前被重置。
    • 但是请避免无意义地调用 persist(),因为它会导致事件对象无法回收,增加内存压力。
  2. 如何优化大量列表元素的事件监听?

    • 利用 React 自身的事件委托,只需在根节点或片段最外层绑定一次事件,避免在每个列表项上重复绑定。
    • 如果某个列表项需要单独事件回调,可在渲染时将同一个处理函数作为 onClick 传入,不要使用匿名箭头函数,避免不断创建新函数。
  3. 钩子函数捕获旧值的问题

    • useEffectsetTimeoutPromise 等异步场景中,事件回调中的变量会被闭包“冻结”为当时的值。
    • 可通过将回调包裹在 useCallback 中并添加相应依赖,或者使用 useRef 保存最新值来解决。
  4. 阻止默认行为与原生 API 的区别

    • event.preventDefault() 是阻止 React 合成事件中对应的默认行为(最终会作用于浏览器原生事件)。
    • 如果想阻止浏览器原生事件的后续监听器执行,需要调用 event.nativeEvent.stopImmediatePropagation()。但这是一个“后门”方法,应谨慎使用。
  5. 在 React 中使用原生事件监听时机

    • 使用 useEffect 在组件挂载时手动注册原生事件监听(如 window.addEventListener('scroll', handleScroll)),并在卸载时移除。
    • 注意与 React 合成事件的顺序,避免重复触发或冲突。例如,若同一元素既有 onClick 又用 addEventListener('click', …),触发顺序会有所不同,需在调试时明确优先级。

十、总结

本文从以下几个方面对 React 事件系统 进行了深度剖析:

  1. 合成事件(Synthetic Event)

    • 统一跨浏览器 API,提供与原生事件一致的接口。
    • 事件池优化,减少频繁创建对象、节约内存。
    • event.persist() 取消池化,保留完整事件对象用于异步访问。
  2. 事件委托(Event Delegation)

    • React 在根节点统一监听并分发事件,大幅减少事件绑定数量。
    • 通过 event.target 与组件 fiber 树关联,定位真正的触发源并调用相应回调。
  3. 事件传播(Propagation)

    • 支持捕获(onClickCapture)与冒泡(onClick)阶段的事件绑定。
    • event.stopPropagation()event.nativeEvent.stopImmediatePropagation() 的区别与使用场景。
  4. Hook 环境下的事件使用注意

    • 及时处理闭包捕获的旧状态值问题。
    • 异步操作中访问事件需先调用 event.persist()
    • 可配合 useCallbackuseRef 保证事件回调与最新状态同步。
  5. 高级实战示例

    • HOC 中统一劫持、埋点事件。
    • 原生事件与合成事件联动。
    • 响应式、可扩展的自定义事件分发方案。

通过这篇文章,你应该对 React 事件系统的内部机制有了全面且深入的理解。在实际项目中,可以利用这些原理和技巧,编写更简洁、高效且易维护的事件处理逻辑,让你的交互体验更加流畅、代码更具可读性。

最后修改于:2025年05月29日 11:40

评论已关闭

推荐阅读

DDPG 模型解析,附Pytorch完整代码
2024年11月24日
DQN 模型解析,附Pytorch完整代码
2024年11月24日
AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日