跟着MDN学HTML_day_45:(EventTarget接口)

跟着 MDN 学 HTML day_45:深入理解 EventTarget 接口


📑 目录

左列章节 右列章节
[一、EventTarget 接口概述](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [二、EventTarget 构造函数](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[三、addEventListener 基本用法](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [四、listener 参数的两种形式](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[五、options 参数详解](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [六、options 兼容性检测](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[七、使用 AbortSignal 移除监听器](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [八、事件监听器中的 this 指向](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[九、与监听器进行数据交换](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [十、removeEventListener 匹配规则](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[十一、dispatchEvent 手动派发事件](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践) [十二、被动事件与性能优化](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)
[十三、内存管理与最佳实践](#左列章节 右列章节 一、EventTarget 接口概述 二、EventTarget 构造函数 三、addEventListener 基本用法 四、listener 参数的两种形式 五、options 参数详解 六、options 兼容性检测 七、使用 AbortSignal 移除监听器 八、事件监听器中的 this 指向 九、与监听器进行数据交换 十、removeEventListener 匹配规则 十一、dispatchEvent 手动派发事件 十二、被动事件与性能优化 十三、内存管理与最佳实践)

一、EventTarget 接口概述

EventTarget 接口由可以接收事件并且可以创建事件侦听器的对象实现。简而言之,只要一个对象能够成为事件的目标,它就必然实现了与这个接口相关的三个方法:addEventListenerremoveEventListenerdispatchEvent

在浏览器环境中,ElementDocumentWindow 是最常见的事件目标。除此之外,XMLHttpRequestAudioNodeAudioContext 等对象同样可以作为事件目标。

代码示例:验证常见对象是否继承自 EventTarget
javascript 复制代码
console.log(document instanceof EventTarget);       // true
console.log(window instanceof EventTarget);          // true
console.log(document.body instanceof EventTarget);   // true

许多事件目标还支持通过 onevent 属性或 HTML 特性设置事件处理程序,例如 onclickonload 等,这是比 addEventListener 更早期的用法,但 addEventListener 提供了更精细的控制能力。


⚠️ 【重点 / 面试考点】

  • EventTarget 是 DOM 事件体系的基石接口,所有能接收事件的对象都实现了它
  • ElementDocumentWindow 是最常见的事件目标,但 XMLHttpRequestAudioNode 等也实现了此接口
  • addEventListener 相比 onXYZ 属性具有多监听器阶段控制移除能力等显著优势

二、EventTarget 构造函数

EventTarget 构造函数用于创建一个新的 EventTarget 对象实例。在实际开发中,显式调用此构造函数的情况极为少见,多数情况下它是在子类的构造函数中通过 super 关键字被间接调用的。

代码示例:直接使用 EventTarget 构造函数
javascript 复制代码
const myTarget = new EventTarget();
console.log(myTarget instanceof EventTarget); // true

更常见的场景是创建一个继承自 EventTarget 的自定义类,从而让这个类的实例拥有完整的事件能力。

代码示例:自定义事件目标类
javascript 复制代码
class MyEventTarget extends EventTarget {
  constructor(mySecret) {
    super();
    this._secret = mySecret;
  }

  get secret() {
    return this._secret;
  }
}

let myEventTarget = new MyEventTarget(5);
console.log(myEventTarget.secret); // 5

myEventTarget.addEventListener("foo", (e) => {
  myEventTarget._secret = e.detail;
});

let event = new CustomEvent("foo", { detail: 7 });
myEventTarget.dispatchEvent(event);
console.log(myEventTarget.secret); // 7

核心结论:这个例子展示了一个完整的事件通信流程------创建自定义事件目标、注册事件监听器、构造并派发自定义事件,最终实现了数据的更新。这种模式在前端组件化架构和状态管理中非常实用。


三、addEventListener 方法的基本用法

addEventListenerEventTarget 上最常用的方法,它用于在事件目标上注册特定事件类型的处理程序。其核心语法为 addEventListener(type, listener),也可以通过第三个参数传递 options 对象或 useCapture 布尔值。

代码示例:基本的 click 事件监听
javascript 复制代码
const button = document.getElementById("myButton");
button.addEventListener("click", function(event) {
  console.log("按钮被点击了");
  console.log("事件类型:", event.type);
});

与传统的 onXYZ 属性绑定相比,addEventListener 具有显著优势。它允许为同一个事件类型添加多个监听器,这在需要兼容第三方库或模块化代码时尤为重要。

代码示例:同一事件的多个监听器
javascript 复制代码
button.addEventListener("click", () => console.log("监听器 1"));
button.addEventListener("click", () => console.log("监听器 2"));
button.addEventListener("click", () => console.log("监听器 3"));
// 单次点击将依次输出三条信息

此外,addEventListener任何事件类型都有效,而不仅限于 HTML 或 SVG 元素上预定义的事件。


四、listener 参数的两种形式

addEventListenerlistener 参数可以是一个回调函数 ,也可以是一个实现了 EventListener 接口的对象 ,即拥有 handleEvent 方法的对象。

使用函数作为监听器是最常见的形式:

代码示例:函数作为监听器
javascript 复制代码
window.addEventListener("resize", function(event) {
  console.log("窗口大小发生变化,当前宽度:", window.innerWidth);
});

使用对象作为监听器则提供了更好的组织性和复用性:

代码示例:对象作为监听器(handleEvent)
javascript 复制代码
const eventHandler = {
  handleEvent: function(event) {
    switch (event.type) {
      case "click":
        console.log("处理点击事件");
        break;
      case "keydown":
        console.log("处理键盘事件,键值:", event.key);
        break;
    }
  }
};

document.addEventListener("click", eventHandler);
document.addEventListener("keydown", eventHandler);

核心结论handleEvent 方式允许将多个事件的处理逻辑集中在一个对象中,使得代码结构更加清晰,也便于后续的移除操作。


⚠️ 【重点 / 面试考点】

  • listener 参数的两种合法形式:回调函数带有 handleEvent 方法的对象
  • 使用对象形式时,事件触发后会自动调用 handleEvent 方法,并将事件对象传入
  • 对象形式的优势在于多事件复用同一处理器便于移除逻辑集中管理

五、options 参数详解

addEventListener 的第三个参数从最初的 useCapture 布尔值演变为功能更丰富的 options 对象,支持以下配置项。

代码示例:capture 选项(捕获阶段控制)
javascript 复制代码
// 捕获阶段触发
parentElement.addEventListener("click", handler, { capture: true });
// 冒泡阶段触发(默认)
parentElement.addEventListener("click", handler, { capture: false });
代码示例:once 选项(单次监听)
javascript 复制代码
button.addEventListener("click", function() {
  console.log("这条信息只会输出一次");
}, { once: true });
代码示例:passive 选项(性能优化声明)
javascript 复制代码
document.addEventListener("touchstart", handler, { passive: true });
代码示例:signal 选项(AbortController 移除)
javascript 复制代码
const controller = new AbortController();
element.addEventListener("click", handler, { signal: controller.signal });
// 通过调用 controller.abort() 即可移除该监听器

六、options 支持的浏览器兼容性检测

由于旧版浏览器仍然假定 addEventListener 的第三个参数是布尔值,开发者在使用 options 对象时需要进行特性检测。以下是一个检测 passive 选项是否受支持的经典方案。

代码示例:检测 passive 选项的支持情况
javascript 复制代码
let passiveSupported = false;

try {
  const options = {
    get passive() {
      passiveSupported = true;
      return false;
    }
  };
  window.addEventListener("test", null, options);
  window.removeEventListener("test", null, options);
} catch (err) {
  passiveSupported = false;
}

console.log("passive 是否受支持:", passiveSupported);

原理解析 :如果浏览器将第三个参数视为对象,就会尝试读取 passive 属性,从而触发 getter 函数并将标识设为 true

检测之后可以据此决定如何调用 addEventListener

javascript 复制代码
element.addEventListener(
  "mouseup",
  handleMouseUp,
  passiveSupported ? { passive: true } : false
);

七、使用 AbortSignal 移除监听器

AbortSignal 提供了一种优雅地移除事件监听器的方式,特别适用于需要在某些条件满足后自动取消监听的场景。

代码示例:AbortSignal 自动移除监听器
javascript 复制代码
const controller = new AbortController();
const targetElement = document.getElementById("clickArea");

targetElement.addEventListener("click", function() {
  console.log("区域被点击");
  // 当满足特定条件时,终止监听
  controller.abort();
}, { signal: controller.signal });

核心结论 :在 controller.abort() 被调用后,对应的监听器即被移除,无需再手动调用 removeEventListener。这在处理复杂的条件逻辑或需要批量移除多个监听器时特别方便。


⚠️ 【重点 / 易错点】

  • AbortSignal 是现代浏览器中替代 removeEventListener 的推荐方案
  • 一个 AbortController 可以同时控制多个监听器 的移除,只需将它们共用同一个 signal
  • controller.abort() 调用后,所有使用该 signal 的监听器都会被一次性移除
  • 适用于组件卸载、路由切换等需要批量清理事件的场景

八、事件监听器中的 this 指向问题

在使用 addEventListener 注册事件处理器时,处理器函数内部的 this默认指向触发事件的元素

代码示例:普通函数中的 this 指向
javascript 复制代码
const myElement = document.getElementById("demo");
myElement.addEventListener("click", function(e) {
  console.log(this === e.currentTarget); // true
  console.log(this.id); // "demo"
});

然而,箭头函数没有自己的 this 上下文 ,它会继承定义时所在作用域的 this

代码示例:箭头函数中的 this 指向
javascript 复制代码
myElement.addEventListener("click", (e) => {
  console.log(this === e.currentTarget); // false
  // 此处的 this 指向外层作用域
});

如果需要在监听器中使用特定的 this 值,可以使用 Function.prototype.bind()

代码示例:使用 bind 绑定自定义 this
javascript 复制代码
const customThis = { name: "自定义上下文" };
myElement.addEventListener("click", function() {
  console.log(this.name); // "自定义上下文"
}.bind(customThis));

在 HTML 属性中直接编写事件处理代码时,this 同样指向当前元素。

html 复制代码
<button id="myButton" onclick="console.log(this.id)">点击</button>

但如果在属性中调用全局函数,则 this 在非严格模式下指向 window 对象。

html 复制代码
<script>
  function showThis() {
    console.log(this); // window(非严格模式)
  }
</script>
<button onclick="showThis()">点击</button>

九、与监听器进行数据交换

事件监听器的参数列表只有 event 一个参数,如何才能向监听器传入额外的数据?有三种常见方式。

第一种是使用 bind 方法绑定数据到 this

代码示例:通过 bind 传入数据
javascript 复制代码
const data = "传入的数据";
element.addEventListener("click", function() {
  console.log(this); // "传入的数据"
}.bind(data));

第二种是利用外部作用域的变量

代码示例:利用闭包共享数据
javascript 复制代码
let sharedData = "初始值";
element.addEventListener("click", () => {
  console.log(sharedData);
  sharedData = "更新后的值";
});

第三种是通过对象引用进行数据交换,由于对象以引用方式存储,多个函数可以共享和修改同一个对象:

代码示例:通过对象引用交换数据
javascript 复制代码
const dataContainer = { value: "初始" };

element.addEventListener("click", () => {
  console.log(dataContainer.value);
  dataContainer.value = "已修改";
});

setInterval(() => {
  if (dataContainer.value === "已修改") {
    console.log("检测到数据变更");
    dataContainer.value = "初始";
  }
}, 3000);

核心结论 :这三种方式各有适用场景,对象引用的方式最为灵活,因为修改可跨作用域持久化。


十、removeEventListener 方法与匹配规则

removeEventListener 用于移除之前通过 addEventListener 注册的事件监听器。要成功移除,typelistener 参数必须完全匹配,而 capture 标志也需要一致。

代码示例:removeEventListener 的基本匹配
javascript 复制代码
function handleClick(event) {
  console.log("处理点击");
}

// 添加监听器(冒泡阶段)
element.addEventListener("click", handleClick, false);

// 成功移除(capture 匹配)
element.removeEventListener("click", handleClick, false);

// 如果添加时使用了捕获阶段
element.addEventListener("click", handleClick, true);

// 则必须用相同的 capture 值移除
element.removeEventListener("click", handleClick, false); // 失败
element.removeEventListener("click", handleClick, true);  // 成功

options 对象的各个属性中,只有 capture 会影响 removeEventListener 的匹配结果 ,其他属性如 passiveonce 等不会影响。

代码示例:options 属性对移除匹配的影响
javascript 复制代码
element.addEventListener("mousedown", handleMouseDown, { passive: true });

// 以下均成功移除,因为 capture 默认为 false,且 passive 不影响匹配
element.removeEventListener("mousedown", handleMouseDown, { passive: true });
element.removeEventListener("mousedown", handleMouseDown, { passive: false });
element.removeEventListener("mousedown", handleMouseDown, false);

// 以下失败,因为 capture 标志不匹配
element.removeEventListener("mousedown", handleMouseDown, { capture: true });
element.removeEventListener("mousedown", handleMouseDown, true);

⚠️ 【重点 / 面试考点】

  • removeEventListener 成功移除的三个匹配条件type 一致、listener 引用相同、capture 一致
  • passiveoncesignal 不影响移除匹配 ,只有 capture 起作用
  • 匿名函数无法被移除,因为无法获取到相同的函数引用
  • 推荐使用命名函数AbortSignal 来管理监听器生命周期

十一、dispatchEvent 手动派发事件

dispatchEvent 方法允许开发者以编程方式触发事件 ,它会同步 调用所有受影响的 EventListener,并在所有监听器执行完毕后返回。

代码示例:手动派发自定义事件
javascript 复制代码
const customEvent = new Event("build", { bubbles: true });
element.addEventListener("build", function(e) {
  console.log("自定义 build 事件被触发");
});
element.dispatchEvent(customEvent);

关键区别 :与浏览器原生事件通过事件循环异步调用处理程序不同,dispatchEvent同步执行 所有监听器。在 dispatchEvent 返回之前,所有监听器函数都会执行完毕。

dispatchEvent 的返回值是一个布尔值。如果事件可取消(cancelabletrue)且任意一个监听器调用了 preventDefault,则返回 false;否则返回 true

代码示例:可取消事件的返回值
javascript 复制代码
const cancelableEvent = new Event("action", { cancelable: true });
element.addEventListener("action", function(e) {
  e.preventDefault();
});
const result = element.dispatchEvent(cancelableEvent);
console.log(result); // false,因为 preventDefault 被调用

自定义事件还可以配合 CustomEvent 传递更丰富的数据:

代码示例:使用 CustomEvent 传递数据
javascript 复制代码
const detailEvent = new CustomEvent("update", { detail: { id: 42, name: "新数据" } });
element.addEventListener("update", function(e) {
  console.log("收到数据:", e.detail);
});
element.dispatchEvent(detailEvent);

十二、被动事件与性能优化

passive 选项对滚动相关性能有着重要影响。根据规范,addEventListenerpassive 默认值为 false 。然而,在文档级节点的 wheelmousewheeltouchstarttouchmove 等事件上,大部分现代浏览器会将 passive 默认值改为 true,以防止事件监听器阻塞页面滚动。

代码示例:显式声明 passive 为 false
javascript 复制代码
// 显式声明 passive 为 false 以允许 preventDefault
document.addEventListener("touchstart", function(e) {
  e.preventDefault(); // 阻止默认行为
}, { passive: false });

如果 passive 设为 true 但监听器中仍然调用了 preventDefault,浏览器会忽略该调用并输出控制台警告。

代码示例:passive true 时 preventDefault 被忽略
javascript 复制代码
document.addEventListener("touchstart", function(e) {
  e.preventDefault(); // 被忽略,控制台会警告
}, { passive: true });

核心结论 :使用 passive 可以显著改善滚屏性能,尤其在移动端,应尽可能将不需要阻止默认行为的事件监听器设为被动。


十三、内存管理与最佳实践

匿名函数作为监听器时,每次调用 addEventListener 都会创建一个新的函数实例,这不仅增加内存开销,还会导致无法通过 removeEventListener 移除该监听器。

代码示例:匿名函数的隐患(不推荐)
javascript 复制代码
// 不推荐的写法:每次都是新的匿名函数
for (let i = 0; i < elements.length; i++) {
  elements[i].addEventListener("click", function(e) {
    /* 处理点击 */
  });
}
代码示例:复用命名函数引用(推荐)
javascript 复制代码
// 推荐的写法:复用同一个函数引用
function handleClick(e) {
  /* 处理点击 */
}
for (let i = 0; i < elements.length; i++) {
  elements[i].addEventListener("click", handleClick);
}

核心结论 :在移除含有多个监听器的事件目标时,保持对监听器函数的引用是能否成功移除的关键。出于这个原因,模块化和组件化开发中更推荐使用命名的函数引用 ,或者使用 AbortSignal 来统一管理监听器的生命周期。


十四、EventTarget 核心方法速查

方法 功能说明 核心参数 返回值
addEventListener 注册事件监听器 type, listener, options/useCapture undefined
removeEventListener 移除事件监听器 type, listener, options/useCapture undefined
dispatchEvent 手动派发事件 event(Event 对象) boolean
继承关系示意图

EventTarget
Node
XMLHttpRequest
AudioNode
Window
Element
Document
自定义类

extends EventTarget


✅ 文档总结

  • EventTarget 是 DOM 事件体系的基石接口ElementDocumentWindow 等都继承自它
  • 构造函数 EventTarget() 可以创建独立的事件目标对象,常用于自定义类继承实现组件通信
  • addEventListener 支持多监听器、控制捕获与冒泡阶段、一次性监听、被动监听以及信号移除
  • listener 可以是函数 也可以是具有 handleEvent 方法的对象
  • removeEventListener 的匹配严格要求 typelistener 引用和 capture 三者一致
  • dispatchEvent 可以手动触发事件并同步执行 所有监听器,返回 preventDefault 是否被调用
  • passive 选项对滚动性能优化意义重大,移动端应尽可能设为 true
  • 匿名函数 会带来内存管理和移除上的隐患,推荐使用命名函数或 AbortSignal
  • AbortSignal 是现代浏览器中管理监听器生命周期的推荐方案

完整实践示例
javascript 复制代码
// 创建自定义事件目标
class TaskManager extends EventTarget {
  addTask(name) {
    this.dispatchEvent(new CustomEvent("taskAdded", {
      detail: { taskName: name, timestamp: Date.now() },
      bubbles: true
    }));
  }
}

const manager = new TaskManager();
const controller = new AbortController();

// 注册带 signal 的监听器
manager.addEventListener("taskAdded", (e) => {
  console.log(`任务 "${e.detail.taskName}" 已添加`);
}, { signal: controller.signal });

// 触发事件
manager.addTask("学习 EventTarget");

// 需要时统一移除
// controller.abort();

通过动手实践,可以更直观地体会到 EventTarget 在事件驱动编程中的核心地位和强大能力。


想要解锁更多HTML 核心标签实战、前端零基础入门干货、开发避坑全指南吗?
持续关注,后续将更新CSS 布局实战、JavaScript 交互基础、全站导航开发等硬核内容,带你从新手快速进阶,轻松搞定前端开发!

相关推荐
for_ever_love__1 小时前
UI学习:数据驱动ce l l
学习·ui·ios·objective-c
漂移的电子1 小时前
【el-tree】外层多选,某个属性内层单选
前端·javascript·vue.js
BJ-Giser2 小时前
Cesium 体积光阴影率分析和阴影体渲染效果
前端·可视化·cesium
幽络源小助理2 小时前
YK一点资讯Zblog主题源码, 游戏攻略新闻资讯模板
前端·php源码
RPGMZ2 小时前
RPGMZ NPC头顶自动显示一段消息
前端·游戏引擎·rpgmz·rpgmakermz
陈天伟教授2 小时前
UI-TARS Desktop
人工智能·ui
DFT计算杂谈2 小时前
AMSET 设置多核并行计算
java·前端·css·html·css3
花椒技术2 小时前
AI 协同开发落地复盘:1 小时生成首版后,为什么 Review 和修正又花了 2-3 天
前端·人工智能·架构
特立独行的猫a2 小时前
C++轻量级UI库DuiLib使用指南与优劣解析
c++·ui