news 2026/7/2 7:12:36

淘宝x5sec滑块验证码逆向:slidedata参数生成与自动化过码实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
淘宝x5sec滑块验证码逆向:slidedata参数生成与自动化过码实战

1. 项目概述:从“滑不动”到“自动过”的实战之旅

做电商数据抓取或者自动化操作的朋友,对淘宝的验证码肯定不陌生。尤其是那个经典的滑块验证码,一个拼图块,一条轨道,需要你手动拖到缺口位置。手动操作一两次还行,但如果是需要批量、高频执行的自动化任务,这就是一个必须跨过的技术门槛。今天要聊的,就是这个验证码体系的核心——x5sec滑条验证码中,那个至关重要的slidedata参数。这个参数不是你简单模拟一下鼠标轨迹就能生成的,它是淘宝前端安全体系x5sec计算出来的一串“通关文牒”,包含了你的滑动行为是否“像人”的所有证据。逆向这个参数,并构建一套稳定的自动化过码方案,是打通淘宝数据自动化链路的关键一步。无论你是做竞品分析、价格监控,还是研究风控策略,掌握这套方法,都能让你从“手动点点点”的困境中解放出来,实现真正的自动化。

2. 核心需求与逆向目标解析

2.1 为什么是slidedata

在触发淘宝滑块验证码后,当你完成滑动并松开鼠标,浏览器会向验证服务器发送一个验证请求。这个请求的 payload 里,最关键的就是slidedata参数。它是一长串看似随机的字符,通常以 Base64 编码形式出现。服务器端会解密并校验这串数据,里面至少包含了以下核心信息:

  1. 滑动轨迹数据:记录了鼠标从按下到松开过程中,每一毫秒(或一个采样间隔)的坐标位置(x, y)和时间戳t。这是判断操作是否由真人执行的核心依据。
  2. 滑动行为特征:基于轨迹数据计算出的衍生特征,如平均速度、加速度变化、是否有停顿、滑动路径的弯曲程度等。机器生成的直线匀速轨迹在这里很容易被识别。
  3. 环境指纹信息:可能与浏览器或客户端的某些特征值绑定,确保这次滑动请求和之前加载验证码的请求来自同一个“环境”,防止参数被复用或重放。
  4. 加密签名:对上述所有数据,使用只有服务器和合法前端才知道的密钥(或算法)进行签名,防止数据被篡改。

因此,我们的逆向目标非常明确:完整复现前端生成slidedata参数的整个逻辑链。这不仅仅是找到加密函数,还要理解其数据构造、轨迹模拟、特征计算和最终加密签名的全过程。

2.2 逆向工程的整体思路

面对一个成熟的前端安全方案,直接硬啃混淆后的代码效率很低。一个高效的逆向思路通常是:

  1. 定位关键请求:使用浏览器开发者工具(F12)的 Network 面板,在滑块滑动完成后,寻找向*verify*,*x5sec*,*slide*等关键词的接口发出的 POST 请求。找到携带slidedata的那个请求。
  2. 追踪参数生成:以slidedata为线索,在发起该请求的 JavaScript 代码处打上 XHR/Fetch 断点,或者搜索slidedata这个字符串在源码中的出现位置,从而定位到生成该参数的函数。
  3. 逆向加密逻辑:目标函数往往经过混淆、压缩。我们需要通过静态分析(阅读代码逻辑)和动态调试(Console 打印、断点观察变量值)相结合的方式,理清其输入、输出和内部处理流程。重点关注:
    • 轨迹生成算法slidedata的明文(或中间结构)是什么格式?
    • 特征计算方式:如何从原始坐标序列计算出那些行为特征?
    • 加密/编码方式:最后是用了 AES、RSA,还是自定义的编码?密钥从哪里来?
  4. 模拟与复现:在 Node.js 或 Python 环境中,用代码还原整个生成流程。难点在于完美模拟“人类”滑动轨迹,以及处理可能存在的随机因子和环境绑定。

注意:淘宝的x5sec方案会持续更新,包括算法变更、混淆加强、接口变动等。本文分享的是一种通用的、方法论层面的逆向思路和应对策略,具体的代码实现和函数名可能会随时间失效,但解决问题的路径是相通的。

3. 逆向实战:深入x5sec核心逻辑

3.1 环境准备与关键请求捕获

工欲善其事,必先利其器。我们需要一个能方便调试和分析的环境。

  1. 浏览器选择:推荐使用 Chrome 或基于 Chromium 的新版 Edge。它们的开发者工具功能强大且稳定。
  2. 开启无痕模式:避免浏览器插件对页面 JavaScript 环境造成干扰。
  3. 访问验证码触发页面:通常,在淘宝登录失败几次后,或在某些敏感操作(如批量搜索)时,会弹出滑块验证。也可以寻找一些公开的测试点。
  4. 打开开发者工具:按 F12,切换到Network(网络)面板。勾选Preserve log(保留日志),防止页面跳转后请求记录被清空。在筛选框输入verifyslide进行过滤。
  5. 触发并完成滑动:手动滑动拼图到正确位置。此时,Network 面板会捕获到一系列新的请求。

在这些请求中,你需要找到一个状态码为200的POST请求,其 URL 可能包含x5secverify等关键词。点击这个请求,查看HeadersPayload。在Payloadform datarequest payload中,你就能看到我们的目标——slidedata,它可能和其他参数如tokenscene等在一起。

3.2 逆向入口定位与代码追踪

找到请求后,下一步是找到生成这个slidedata的 JavaScript 代码。

  1. Initiator 调用栈:在 Network 面板中,点击那个携带slidedata的请求,查看右侧的Initiator标签页。这里显示了是哪个脚本文件、哪一行代码发起了这个网络请求。点击那个脚本链接,可以直接跳转到Sources(源代码)面板的对应位置。
  2. 搜索大法:如果调用栈不明显,可以在Sources面板中,按Ctrl+Shift+F(Windows) 或Cmd+Opt+F(Mac) 进行全局搜索。搜索关键词slidedataslideData。由于代码被压缩,变量名可能是单字母,但字符串常量通常保留。
  3. XHR/Fetch 断点:这是一个更精准的方法。在Sources面板,找到右侧的XHR/Fetch Breakpoints,点击+号,添加一个断点,输入包含验证接口 URL 关键词(如verify)的字符串。当浏览器发起任何包含该关键词的请求时,代码执行会自动暂停,此时调用栈会清晰地指向生成请求参数的函数。

一旦在源代码中定位到关键函数(可能是一个被混淆成function a(b, c, d)的函数),真正的逆向就开始了。

3.3 核心算法拆解:轨迹、特征与加密

假设我们通过断点,进入了一个名为generateSlideData(track)的函数(实际函数名可能极其简单)。我们需要理清它的内部逻辑。

3.3.1 轨迹数据构造

首先,函数会接收一个轨迹数组track。这个数组的每个元素可能是一个对象,如{x: 100, y: 5, t: 1630000000000},分别代表横坐标、纵坐标(通常变化很小)和时间戳(毫秒)。

// 伪代码示意 let humanTrack = simulateHumanSlide(startX, endX, step); // humanTrack 可能形如: // [ // {x: 0, y: 2, t: 1630000000000}, // {x: 15, y: 3, t: 1630000000012}, // {x: 30, y: 1, t: 1630000000025}, // ..., // {x: 260, y: 4, t: 1630000000150} // ]

人类轨迹模拟的关键点

  • 非匀速:先加速,后匀速,再减速。起始和结束阶段速度慢。
  • 微小抖动:在y轴方向上有1-5像素的随机抖动,模拟手部不稳。
  • 随机停顿:在滑动路径中,有极低概率插入一个几十毫秒的停顿。
  • 路径弯曲:轨迹并非绝对直线,而是有非常轻微的“S”形或弧形弯曲。

3.3.2 特征值计算

接着,函数会根据原始轨迹计算一系列特征。这些特征是风控模型判断人机差异的核心。常见的计算可能包括:

  • 总耗时totalTime = track[last].t - track[0].t
  • 平均速度avgSpeed = (endX - startX) / totalTime
  • 加速度序列:根据相邻点的速度差和时间差计算。
  • 轨迹拟合度:计算轨迹点与一条理想直线的偏离程度。
  • 抖动方差:计算y坐标序列的方差。
  • 时间间隔分布:检查各点时间间隔是否均匀。

这些计算后的特征值,可能会被归一化或量化,然后与原始轨迹数据一起,组装成一个结构化的对象,我们称之为待加密明文对象

3.3.3 加密与编码

最后,这个明文对象会被序列化(如 JSON.stringify)并加密。

  1. 加密算法:常见的是AES加密。你需要通过代码分析找到加密模式(如 CBC)、填充方式(如 PKCS7)和密钥(Key)初始向量(IV)。密钥可能是硬编码在 JS 中的某个常量字符串,也可能是通过更复杂的方式从页面其他元素或早期请求中计算得来。
  2. 编码输出:加密后得到的通常是二进制数据(字节数组)。为了在 HTTP 请求中传输,会进行一次Base64编码。最终,这个 Base64 字符串就是slidedata参数的值。
// 伪代码示意核心流程 function generateSlideData(humanTrack) { // 1. 计算特征 let features = calculateFeatures(humanTrack); // 2. 组装明文数据 let plainData = { track: humanTrack, features: features, token: pageToken, // 来自页面的某个令牌 ct: Date.now(), // 客户端时间戳 // ... 其他环境信息 }; // 3. 序列化 let jsonString = JSON.stringify(plainData); // 4. 加密 (例如 AES-CBC-PKCS7) let encryptedBytes = aesEncrypt(jsonString, secretKey, iv); // 5. Base64 编码 let slidedata = base64Encode(encryptedBytes); return slidedata; }

逆向的过程,就是通过调试,还原出calculateFeaturesaesEncrypt以及secretKeyiv的获取逻辑。

4. 自动化过码方案设计与实现

逆向分析完成后,我们就可以着手设计自动过码方案了。一个健壮的方案通常包含以下几个模块。

4.1 方案架构设计

我们的自动化方案不应该是一个脆弱的、硬编码的脚本,而应该是一个具备一定自适应能力的系统。核心架构可以分为四层:

  1. 感知层:负责获取验证码图片、缺口位置信息。可以通过对接打码平台(如超级鹰、图鉴)的 API,或者使用本地 OpenCV 模板匹配算法来识别缺口。
  2. 决策层:根据缺口位置,生成模拟人类的滑动轨迹。这是方案的核心,轨迹的质量直接决定通过率。
  3. 执行层:负责执行逆向逻辑。它需要能够动态加载或执行还原出的 JavaScript 加密函数,输入轨迹数据,输出正确的slidedata。这可以通过 PyExecJS、Node.js 子进程或无头浏览器(如 Puppeteer)来实现。
  4. 交互层:负责与淘宝页面进行通信,包括触发验证码、提交验证请求、处理验证结果。
[感知层:缺口识别] -> [决策层:轨迹生成] -> [执行层:slidedata计算] -> [交互层:提交验证]

4.2 人类轨迹生成算法

这是区分初级和高级方案的关键。一个简单的匀速直线轨迹几乎必败。我们需要模拟得更像真人。

import random import time def generate_human_track(distance, total_time_ms=2000): """ 生成人类滑动轨迹 :param distance: 需要滑动的总水平距离(像素) :param total_time_ms: 计划总耗时(毫秒) :return: 轨迹列表,每个元素为 (x_offset, y_offset, timestamp_ms) """ track = [] current_x = 0 current_y = 0 current_time = 0 # 阶段划分:加速段(30%),匀速段(40%),减速段(30%) accelerate_end = int(total_time_ms * 0.3) uniform_end = int(total_time_ms * 0.7) # 初始速度设为0,目标平均速度 avg_speed = distance / total_time_ms # 设置一个峰值速度,略高于平均速度 peak_speed = avg_speed * random.uniform(1.3, 1.7) v = 0 # 当前速度 a = peak_speed / accelerate_end # 加速度 while current_time < total_time_ms: # 1. 计算当前时刻的理论速度 if current_time < accelerate_end: # 加速阶段 v = a * current_time elif current_time < uniform_end: # 匀速阶段 v = peak_speed else: # 减速阶段 decelerate_time = current_time - uniform_end decelerate_duration = total_time_ms - uniform_end v = peak_speed * (1 - decelerate_time / decelerate_duration) # 2. 计算本时间步长内的位移(假设每步10ms) step_ms = 10 dx = v * step_ms # 添加水平方向的微小随机扰动(±0.5像素) dx += random.uniform(-0.5, 0.5) # 3. 计算垂直方向抖动(模拟手抖) dy = random.uniform(-3, 3) # 确保y轴抖动整体围绕0波动,不产生系统性偏移 if len(track) > 5: # 简单平滑:当前抖动受前几个点影响 dy = dy * 0.3 + sum([p[1] for p in track[-3:]]) / 3 * 0.7 current_x += dx current_y += dy # 4. 确保不超出边界 if current_x > distance: current_x = distance v = 0 # 5. 随机插入微小停顿(5%概率) if random.random() < 0.05 and current_time > total_time_ms * 0.2: step_ms += random.randint(15, 40) # 增加停顿时间 current_time += step_ms track.append((round(current_x, 2), round(current_y, 2), round(current_time, 2))) # 如果已到达终点,提前退出循环 if abs(current_x - distance) < 1: # 补一个终点记录 track.append((distance, current_y, total_time_ms)) break # 后处理:确保最后一个点精确在终点,总时间符合预期 if track[-1][0] != distance: track.append((distance, track[-1][1], total_time_ms)) return track # 示例:生成一个滑动260像素,耗时约2秒的轨迹 slide_distance = 260 human_track = generate_human_track(slide_distance, 2100)

这个算法模拟了加速、匀速、减速的过程,加入了垂直抖动和随机停顿,生成的轨迹比简单的匀加速-匀减速模型更加拟真。

4.3 加密逻辑的本地化执行

我们无法直接调用淘宝页面里的 JavaScript 函数,但可以通过一些技术手段在本地环境中复现。

方案一:PyExecJS / Js2Py(Python)适用于加密逻辑相对独立、不重度依赖浏览器环境的情况。

import execjs # 1. 将逆向出来的关键JS代码保存到文件,或作为字符串 with open('taobao_slide_encrypt.js', 'r', encoding='utf-8') as f: js_code = f.read() # 2. 创建JS执行上下文 ctx = execjs.compile(js_code) # 3. 调用函数,传入轨迹数据 track_data = [...] # 你的轨迹数组 slidedata = ctx.call('generateSlideData', track_data)

缺点:如果 JS 代码依赖windowdocument等浏览器特有对象,需要手动构造这些环境,比较麻烦。

方案二:Node.js 子进程(Python调用)如果 JS 逻辑复杂,且已用 Node.js 完整还原,这是最稳定的方式。

import subprocess import json def get_slidedata_via_node(track): # 将轨迹数据序列化为JSON字符串 track_json = json.dumps(track) # 构造Node.js命令 cmd = ['node', 'taobao_slide_node.js', track_json] # 执行并获取输出 result = subprocess.run(cmd, capture_output=True, text=True, timeout=5) if result.returncode == 0: return result.stdout.strip() else: raise Exception(f"Node.js process failed: {result.stderr}")

taobao_slide_node.js文件中,你导出生成slidedata的函数,并通过命令行参数接收轨迹数据。

方案三:无头浏览器(Puppeteer/Playwright)这是最“重”但也是最模拟真实浏览器环境的方法。直接控制一个无头浏览器加载页面,在页面上下文中执行 JS。

# 使用 playwright-python 示例 async def get_slidedata_with_browser(track): from playwright.async_api import async_playwright async with async_playwright() as p: browser = await p.chromium.launch(headless=True) context = await browser.new_context() page = await context.new_page() # 1. 导航到目标页面(可能需要处理登录态) await page.goto('https://target.taobao.com/page-with-captcha') # 2. 注入轨迹数据,并调用页面中的全局函数(假设存在) slidedata = await page.evaluate(f""" (track) => {{ // 这里直接调用页面环境中已存在的函数 return window.generateSlideData(track); }} """, track) await browser.close() return slidedata

优点:环境最真实,能应对复杂的环境依赖。缺点:资源消耗大,速度慢,不适合高并发场景。

实操心得:在实际项目中,我推荐“Node.js子进程”方案。它平衡了性能、稳定性和开发复杂度。我们将核心的逆向JS代码封装成一个Node.js模块,它只负责最纯粹的加密计算,不涉及任何页面操作。Python主程序负责轨迹生成、网络请求和流程控制,通过子进程调用Node模块获得slidedata。这样解耦清晰,也便于后续单独更新加密逻辑。

4.4 完整流程集成与测试

将以上所有模块串联起来,形成一个完整的自动化流程:

  1. 触发验证码:通过自动化工具(如Selenium、Playwright)访问目标页面,执行可能触发验证码的操作(如登录、搜索)。
  2. 获取缺口位置
    • 截图验证码区域。
    • 将背景图和缺口图发送给打码平台API,返回缺口x坐标。
    • (或使用OpenCV进行本地模板匹配,但打码平台通常更稳定)
  3. 生成轨迹:根据缺口位置,调用generate_human_track函数生成轨迹数组。
  4. 计算slidedata:将轨迹数组传入本地化执行的加密模块,得到slidedata字符串。
  5. 构造请求:收集验证接口所需的其他参数(如token,scene等,这些通常可以从页面HTML或之前的请求响应中提取)。
  6. 提交验证:向验证接口发送POST请求,携带slidedata等参数。
  7. 处理结果:解析响应,如果成功,会返回一个pass的令牌或标识;如果失败,分析原因(轨迹不像人、token过期、环境异常等),并可能进入重试逻辑。
# 伪代码集成示例 def auto_slide_captcha(page_client, captcha_img_bg, captcha_img_gap): """自动化处理滑块验证码""" # 1. 识别缺口距离 gap_distance = ocr_or_api_recognize_gap(captcha_img_bg, captcha_img_gap) # 2. 生成人类轨迹 human_track = generate_human_track(gap_distance) # 3. 计算slidedata (通过Node.js子进程) slidedata = get_slidedata_via_node(human_track) # 4. 获取其他必要参数(从page_client上下文中) verify_token = page_client.get_verify_token() scene = page_client.get_scene() # 5. 构造并发送验证请求 payload = { 'token': verify_token, 'scene': scene, 'slidedata': slidedata, # ... 其他固定或动态参数 } verify_url = 'https://sec.taobao.com/x5sec/verify' response = requests.post(verify_url, data=payload, headers=headers) result = response.json() if result.get('success') and result.get('data', {}).get('pass'): print("验证码通过!") return result['data']['verify_token'] # 返回后续可用的令牌 else: print(f"验证失败: {result}") return None

5. 常见问题排查与实战技巧

在实际操作中,你会遇到各种各样的问题。下面是一些典型问题及其排查思路。

5.1 验证成功率低

这是最常见的问题,可能的原因和解决方案如下:

问题现象可能原因排查与解决思路
直接返回“操作过快”或“验证失败”轨迹过于简单,被风控模型直接拒绝。优化轨迹生成算法,增加更丰富的人类行为特征,如更自然的加速度曲线、更真实的抖动模式。
成功率随时间下降淘宝更新了风控模型或加密算法。定期(如每周)重新触发验证码,抓包分析新的slidedata格式和长度。对比新旧JS代码差异。建立算法版本监控。
只在特定环境成功slidedata计算依赖浏览器指纹或环境参数。仔细分析加密函数,看是否使用了navigator.userAgent,screen.width/height, 或某个页面全局变量。在本地执行时需模拟这些值。
偶尔成功,大部分失败轨迹中的随机因子不够“人性化”,或存在特征值异常。记录失败时的轨迹数据,与成功时的轨迹进行对比分析。检查总耗时、平均速度、终点抖动等统计特征是否在合理范围内。

实操心得:轨迹的“人性化”调试不要闭门造车。可以写一个脚本,将生成的轨迹数据可视化出来(用matplotlib画路径图、速度-时间图)。同时,手动滑动几次,用浏览器控制台记录下真实的轨迹数据(需要事先在生成slidedata的函数入口处打日志)。对比机器生成和真人滑动的图表差异,你会直观地发现机器轨迹往往在速度曲线上过于平滑,在路径上过于笔直。针对性地加入符合真人特征的“不完美”变量,是提升通过率的诀窍。

5.2 加密函数依赖外部变量

逆向出来的JS函数,可能依赖一个来自服务器下发的、动态变化的密钥,或者一个由页面其他JS计算出的值。

  • 现象:直接执行加密函数,结果与浏览器中生成的不同。
  • 排查
    1. 在浏览器中,于加密函数入口设置断点。
    2. 单步执行,观察所有用到的变量值。特别注意那些不是由函数参数传入,而是从外层作用域读取的变量(如window._secretKey,globalToken)。
    3. 追踪这些变量的来源。它们可能是在页面加载时由另一个JS脚本初始化,也可能是通过一个异步请求从服务器获取的。
  • 解决
    • 如果变量是固定值,直接硬编码到你的本地JS文件中。
    • 如果变量是动态的,你需要复现获取它的逻辑。这可能意味着你需要先模拟一个前置请求,来获取这个密钥或令牌,然后再执行加密。

5.3 请求参数不完整导致失败

slidedata只是验证请求的一部分。缺少其他必要参数也会导致失败。

  • 关键参数
    • token: 通常在一次验证会话开始时,由服务器下发,存在于页面HTML或一个初始化接口的响应中。
    • scene: 验证场景标识,固定值或根据页面而定。
    • csessionid: 会话ID,可能从cookie或初始化响应中获取。
  • 排查方法:在浏览器中成功完成一次手动验证,仔细检查提交的Form DataRequest Payload,记录下所有参数名和值。在你的自动化脚本中,确保完整地收集并提交这些参数。

5.4 环境与频率风控

即使算法完美,过于频繁的请求也会触发IP或设备级别的风控。

  • IP代理池:必须使用高质量的代理IP,并轮换使用。住宅代理比数据中心代理更可靠。
  • 请求间隔:在请求之间添加随机延迟,模拟真人操作间隔。避免在极短时间内连续触发验证。
  • 浏览器指纹:如果使用无头浏览器方案,要注意其指纹与真实浏览器的差异。可以使用一些库来伪装指纹,但需谨慎,过度伪装本身也可能成为特征。
  • 验证令牌复用:一个token通常只能用于一次验证请求。失败后,需要重新加载页面或调用初始化接口获取新的token,不能复用旧的。

最后,逆向和自动化是一个持续对抗的过程。淘宝的安全团队会不断升级他们的防御策略。今天有效的方法,明天可能就会失效。因此,一个健壮的自动化系统,除了核心的算法模块,还应该包含监控告警快速迭代的能力。当通过率异常下降时,能第一时间感知,并启动分析流程,快速定位是轨迹问题、加密问题还是参数问题,从而尽快修复。保持对网络请求和前端代码变化的敏感度,是维持项目长期可用的关键。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 7:11:15

Juicebox终极实战指南:掌握Hi-C三维基因组可视化核心技能

Juicebox终极实战指南&#xff1a;掌握Hi-C三维基因组可视化核心技能 【免费下载链接】Juicebox Visualization and analysis software for Hi-C data - 项目地址: https://gitcode.com/gh_mirrors/ju/Juicebox Juicebox作为专业的Hi-C数据可视化工具&#xff0c;为基因…

作者头像 李华
网站建设 2026/7/2 7:08:38

判断网站谷歌收录:网站不收录?高手自检的5个关键指标

企业团队花费三个季度完成新站代码编写、设计打磨与服务器部署。站长往搜索框敲入一行网址字符。屏幕上仅弹出一行“未找到相关结果”的灰色提示。一天花费4000块钱的带宽开销换不来一位真实访客点击。一份针对两万家北美外贸站的调查表提供了一组参照数字。高达73%的新站点在上…

作者头像 李华
网站建设 2026/7/2 7:06:33

踩坑总结:Spring @Transactional 事务注解的这几个坑,你踩过几个?

前言 最近在做项目的时候&#xff0c;又碰到了Transactional事务失效的问题。说实话&#xff0c;这个注解看似简单&#xff0c;但用不好真的能把人坑惨。今天就把我踩过的几个坑整理出来&#xff0c;都是实战中实打实遇到的问题&#xff0c;希望能帮大家少走点弯路。坑一&#…

作者头像 李华
网站建设 2026/7/2 7:03:41

电子系统散热管理:从芯片级到系统级的优化策略

1. 为什么电子系统需要主动散热管理&#xff1f;在汽车电子和工业控制领域&#xff0c;散热管理一直是系统可靠性的关键瓶颈。以我参与过的某车载ECU项目为例&#xff0c;当环境温度达到45℃时&#xff0c;未优化散热的PCB板温度会在30分钟内飙升到85℃以上&#xff0c;直接导致…

作者头像 李华
网站建设 2026/7/2 7:03:20

js自定义Emitter,实现1对多的事件派发处理

增加监听on、派发事件emit、移除指定监听off、移除所有监听removeAllListenners<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script>class SimpleEventEmitter {/*** 存…

作者头像 李华