Unity动画状态保持:解决SetActive隐藏后动画重置的3种方案
1. 项目概述一个看似简单却棘手的动画状态管理问题在Unity项目开发中尤其是涉及复杂UI流程、剧情演出或者需要动态管理大量游戏对象的场景里我们经常会遇到一个需求暂时隐藏一个带有Animation组件的物体稍后再将其显示出来并期望它能从隐藏前的动画状态继续播放。然而很多开发者都踩过这样一个坑当你简单地通过SetActive(false)或者将GameObject的active属性设为false来隐藏物体后再次激活它时其Animation或Animator组件中的动画状态会被重置到初始状态。这直接导致了动画衔接不连贯、角色动作“跳帧”、UI转场生硬等一系列破坏用户体验的问题。这个问题之所以普遍且棘手是因为它触及了Unity引擎底层对象生命周期管理与动画系统状态维护之间的一个“认知断层”。对于引擎来说禁用Deactivate一个GameObject意味着将其从场景的运行逻辑中完全移除其附带的组件包括Animation/Animator也会被“冻结”并清理掉运行时状态。再次激活时引擎视其为一个“新”的对象所有组件会按照初始配置重新开始。这符合大多数情况下的直觉但对于需要保持连续状态的动画来说就成了一个需要手动解决的“特性”。本篇文章将深入剖析这个问题的根源并提供从原理到实践的多种解决方案。无论你是正在处理一个需要暂停/恢复的过场动画还是一个根据条件动态显示/隐藏的UI特效理解并掌握这些方法都能让你的项目在细节体验上更加专业和流畅。2. 问题根源与核心原理剖析要解决问题首先要理解问题是如何产生的。Unity中动画状态的“重置”并非Bug而是由其对象激活生命周期和动画状态机的工作机制共同决定的。2.1 GameObject.SetActive 的“硬重置”效应GameObject.SetActive(false)是Unity中最常用的隐藏对象的方法。它的行为可以概括为停止所有协程Coroutines和消息调用该对象上所有正在运行的协程会被中断Update、FixedUpdate等生命周期函数停止执行。禁用所有附加的组件所有MonoBehaviour组件会收到OnDisable消息并停止其功能。对于动画系统而言这是关键一步Animation或Animator组件会被强制停止。组件内部记录的所有运行时状态包括当前播放的动画片段Clip名称、归一化时间Normalized Time、播放速度、混合权重等都会被丢弃。当调用SetActive(true)时过程相反组件收到OnEnable消息并重新初始化。对于Animator组件如果其Controller资产中定义了初始状态如“Idle”它会从那个初始状态开始。对于老版的Animation组件如果没有在代码中指定播放哪个动画它就会停留在默认状态。简单来说SetActive更像是对游戏对象的一次“销毁-重建”逻辑上而非“暂停-继续”。2.2 Animation 与 Animator 组件的差异虽然两者都会受SetActive影响但它们的内部机制略有不同解决方案的侧重点也可能不同。Legacy Animation 组件这是Unity较旧的动画系统。它的状态管理相对简单。当你通过animation.Play(“AnimName”)播放一个动画后状态信息保存在组件实例的内存中。禁用对象会直接清空这片内存。重新激活后组件恢复为脚本或检视面板中Play Automatically所指定的状态。Animator 组件Mecanim这是现代Unity项目的主流动画系统基于状态机State Machine。Animator组件拥有一个runtimeAnimatorController引用。禁用对象时整个状态机的运行时实例包括所有层的当前状态、参数、过渡条件都会被清除。重新激活时Animator会重新实例化状态机并从Any State或默认状态开始重新评估导致回到初始状态。理解了这个核心原理我们就可以避开简单地禁用物体转而采用其他方法来“模拟”隐藏效果同时保全动画状态。3. 解决方案一视觉隐藏而非逻辑禁用推荐这是最直接、最可靠的解决方案。核心思想是我们不动物体的激活状态保持activeInHierarchy为true只改变其渲染和交互使其对玩家“不可见”。3.1 禁用 Renderer 组件对于大多数3D物体或2D Sprite隐藏渲染器是最佳选择。// 在需要隐藏时 Renderer renderer gameObject.GetComponentRenderer(); if (renderer ! null) { renderer.enabled false; } // 在需要显示时 renderer.enabled true;优点Animation/Animator组件继续在后台运行状态如播放进度得以完美保持。性能开销极小仅比渲染少一个绘制调用。对象仍然可以接收物理事件、触发器等如果需要。缺点与注意事项物体本身的碰撞体Collider仍然存在。如果这是一个需要隐藏但又不希望被交互或穿过的物体如一堵隐藏的墙你需要同时处理碰撞体。对于复杂的子物体层级可能需要递归地禁用所有渲染器。UI元素如Image,Text不适用此法它们没有Renderer组件。3.2 修改 Transform 位置或缩放将物体移到摄像机之外或者将其缩放设置为零。// 移到远处例如Y轴负方向1000单位 transform.position new Vector3(transform.position.x, transform.position.y - 1000f, transform.position.z); // 或者缩放为0 transform.localScale Vector3.zero;优点简单粗暴对所有物体都有效包括UI。缩放为0时通常碰撞体也会失效取决于物理引擎的配置。缺点与注意事项移出摄像机需要确保这个位置不会干扰场景中其他逻辑如触发器、寻路网格。恢复位置时需要记录原始位置增加了状态管理成本。缩放为0这是更常用的方法。但需要注意某些依赖于Bounds计算的系统如某些遮挡剔除、UI布局组件可能会产生意外行为。同时子物体的局部缩放也会被影响恢复时需谨慎。3.3 针对UI元素的特殊处理Canvas Group对于UGUI系统CanvasGroup组件是管理UI显隐和交互的瑞士军刀。给需要控制的UI根物体添加CanvasGroup组件。通过代码控制其alpha和interactable等属性。CanvasGroup canvasGroup GetComponentCanvasGroup(); if (canvasGroup ! null) { // 隐藏完全透明且不可交互 canvasGroup.alpha 0f; canvasGroup.interactable false; canvasGroup.blocksRaycasts false; // 关键不阻挡射线检测让下层UI可点 // 显示恢复 canvasGroup.alpha 1f; canvasGroup.interactable true; canvasGroup.blocksRaycasts true; }优点完美适用于UI动画状态如Animator控制的UI动画完全不受影响。可以方便地做淡入淡出效果通过插值改变alpha。能精细控制交互性。实操心得在复杂的UI栈管理中我习惯为每一个可独立打开/关闭的UI面板预制体都挂上一个CanvasGroup。这样关闭面板时我只需修改CanvasGroup的属性面板内部的所有动画逻辑比如打开动画播放到一半关闭都能被完美冻结和恢复体验远好于SetActive。4. 解决方案二状态保存与恢复如果项目架构决定了必须使用SetActive(false)例如为了节省性能必须将远离视野的物体完全禁用那么我们就需要在禁用前手动保存动画状态并在启用后恢复。这种方法更复杂但提供了最大的灵活性。4.1 针对 Legacy Animation 组件Animation组件提供了AnimationState来获取当前播放的动画信息。using UnityEngine; using System.Collections.Generic; public class AnimationStateSaver : MonoBehaviour { private Animation anim; private string lastPlayingClipName; private float lastNormalizedTime; private float lastSpeed; void Awake() { anim GetComponentAnimation(); } public void SaveStateBeforeDisable() { if (anim null || !anim.isPlaying) return; // 假设我们只处理当前正在播放的主动画 foreach (AnimationState state in anim) { if (anim.IsPlaying(state.name)) { lastPlayingClipName state.name; lastNormalizedTime state.normalizedTime; lastSpeed state.speed; break; } } } public void RestoreStateAfterEnable() { if (string.IsNullOrEmpty(lastPlayingClipName)) return; if (!anim.GetClip(lastPlayingClipName)) return; // 播放动画并跳转到保存的时间点 anim.Play(lastPlayingClipName); AnimationState state anim[lastPlayingClipName]; state.normalizedTime lastNormalizedTime; state.speed lastSpeed; // 注意直接设置normalizedTime后需要让动画前进一帧来应用状态 anim.Sample(); // 采样应用当前状态 } // 在OnDisable中保存在OnEnable中恢复注意调用顺序 void OnDisable() { SaveStateBeforeDisable(); } void OnEnable() { // 需要延迟一帧恢复确保Animation组件已完全初始化 StartCoroutine(RestoreNextFrame()); } System.Collections.IEnumerator RestoreNextFrame() { yield return null; // 等待下一帧 RestoreStateAfterEnable(); } }4.2 针对 Animator 组件MecanimAnimator的状态恢复更为复杂因为涉及参数Parameters和状态机层级Layers。using UnityEngine; public class AnimatorStateSaver : MonoBehaviour { private Animator animator; private int savedLayerCount; private int[] savedStateFullPathHashes; private float[] savedStateNormalizedTimes; private float[] savedLayerWeights; // 如果需要保存参数可以序列化AnimatorControllerParameters void Awake() { animator GetComponentAnimator(); savedLayerCount animator.layerCount; savedStateFullPathHashes new int[savedLayerCount]; savedStateNormalizedTimes new float[savedLayerCount]; savedLayerWeights new float[savedLayerCount]; } public void SaveState() { if (!animator.gameObject.activeInHierarchy) return; for (int i 0; i savedLayerCount; i) { AnimatorStateInfo stateInfo animator.GetCurrentAnimatorStateInfo(i); savedStateFullPathHashes[i] stateInfo.fullPathHash; // 唯一标识一个状态 savedStateNormalizedTimes[i] stateInfo.normalizedTime; savedLayerWeights[i] animator.GetLayerWeight(i); } // 这里还可以保存Animator的ParametersBool, Float, Int, Trigger } public void RestoreState() { if (!animator.gameObject.activeInHierarchy) return; // 必须先启用Animator并等待一帧让其内部状态机初始化 animator.enabled true; // 恢复层权重 for (int i 0; i savedLayerCount; i) { animator.SetLayerWeight(i, savedLayerWeights[i]); } // 强制跳转到之前的状态和时间点 for (int i 0; i savedLayerCount; i) { if (savedStateFullPathHashes[i] ! 0) { animator.Play(savedStateFullPathHashes[i], i, savedStateNormalizedTimes[i]); } } // 恢复参数此处省略具体代码需根据你的参数类型逐一设置 // animator.SetFloat(Speed, savedSpeed); // animator.SetBool(IsGrounded, savedIsGrounded); // 注意Trigger参数无法保存需要根据逻辑重新触发 } void OnDisable() { SaveState(); } void OnEnable() { if (animator ! null) { StartCoroutine(RestoreNextFrame()); } } System.Collections.IEnumerator RestoreNextFrame() { yield return null; // 等待一帧确保Animator已唤醒 RestoreState(); } }注意事项时机至关重要必须在OnDisable中保存在OnEnable后的下一帧恢复。因为组件的启用/禁用顺序有严格定义。性能开销保存和恢复状态涉及数据拷贝和哈希计算对于高频操作的物体需评估性能。状态哈希AnimatorStateInfo.fullPathHash是恢复状态的关键它唯一对应状态机中的一个节点。参数管理对于复杂的动画状态机除了状态节点还要保存所有驱动状态切换的Animator Parameters否则恢复的状态可能因为参数不匹配而立刻跳转到其他状态。实操心得在大型项目中我曾为需要频繁池化Pooling的角色对象实现过这套状态保存系统。关键在于不仅要保存状态还要在对象回池SetActive(false)和出池SetActive(true)时与对象池管理器协调好保存与恢复的调用时机确保万无一失。这是一项繁琐但收益显著的工作。5. 解决方案三使用动画系统自身的暂停与采样如果你只是需要“暂停”动画而不是完全重置那么利用动画系统自身的功能是更优雅的选择。5.1 控制 Animator 的播放速度将Animator.speed设置为 0可以暂停所有层的动画播放。设置为1恢复。animator.speed 0f; // 暂停 animator.speed 1f; // 恢复优点极其简单状态完全保留。缺点物体仍然可见。需要配合其他隐藏方法如禁用Renderer使用。5.2 使用 Animation Sample 进行“冻结”对于Animation组件你可以通过Animation.Stop()停止播放但保留当前姿势然后通过Animation.Sample()在任意时刻将动画定格在某一帧。animation.Stop(); // 停止播放但保留当前变换 // ... 物体被隐藏或进行其他操作 ... animation.Play(AnimName); animation[AnimName].normalizedTime savedTime; // 跳转到指定时间 animation.Sample(); // 立即采样将模型定格在这一帧 animation.Stop(); // 再次停止保持这个姿势这种方法适用于需要将角色定格在某个特定动作姿势的场景。6. 方案选型与实战场景指南面对多种方案如何选择下面这个表格可以帮助你快速决策场景特征推荐方案理由与注意事项3D/2D场景物体只需视觉隐藏禁用 Renderer (renderer.enabled false)性能最优实现最简单动画状态保持完美。注意处理碰撞体。UI元素UGUI的显隐控制使用 CanvasGroupUI专用方案能同时控制透明度、交互和射线阻挡与Animator无缝配合。必须禁用物体以优化性能如对象池状态保存与恢复方案二唯一能在SetActive下保持状态的方法。复杂度高需为Animation或Animator分别实现。只需暂停动画物体仍需可见/可交互控制 Animator.speed 0最符合“暂停”语义的操作恢复播放毫无痕迹。需要将角色定格在某个动画姿势Animation.Sample() 采样适用于截图、特殊展示等需要精确控制帧的场景。快速原型或简单场景缩放为0 (transform.localScale Vector3.zero)一行代码解决所有类型物体但可能影响布局和子物体恢复时需小心。个人经验总结在绝大多数“隐藏后恢复”的需求中“视觉隐藏”方案方案一都是首选。它规避了Unity对象生命周期的副作用逻辑清晰性能良好。我仅在对象池这种强制使用SetActive的架构中才会采用状态保存恢复方案。对于UICanvasGroup是绝对的标准答案。7. 常见问题与排查技巧实录即使选择了正确的方案在实际开发中也可能遇到一些“坑”。以下是我在实践中总结的常见问题及解决方法。问题1使用了CanvasGroupalpha设为0但UI动画在隐藏时好像还在消耗性能排查检查Animator组件。即使UI不可见如果Animator未暂停它的状态机仍然每帧都在更新和计算过渡。在UI隐藏时将Animator.enabled设为false可以彻底停止其更新。技巧可以写一个扩展方法同时处理CanvasGroup和Animator。public static void SetUIActive(this GameObject uiObj, bool isVisible, bool pauseAnimator true) { CanvasGroup cg uiObj.GetComponentCanvasGroup(); if (cg ! null) { cg.alpha isVisible ? 1f : 0f; cg.blocksRaycasts isVisible; cg.interactable isVisible; } Animator anim uiObj.GetComponentAnimator(); if (anim ! null pauseAnimator) { anim.enabled isVisible; // 隐藏时禁用Animator以省性能 } }问题2通过脚本保存了Animator状态并恢复但恢复后动画播放速度不对或者立刻跳到了其他状态排查参数未保存这是最常见的原因。你只保存了StateInfo但驱动状态机的ParametersFloat, Bool, Int没有保存和恢复。确保在SaveState时遍历animator.parameters并保存值在RestoreState时重新赋值。Trigger类型参数Trigger无法被“保存”因为它是一次性信号。恢复后你需要根据游戏逻辑判断是否需要重新设置animator.SetTrigger这个Trigger。恢复时机过早在OnEnable中直接恢复可能不行因为Animator的OnEnable内部初始化可能还没完成。务必使用yield return null延迟到下一帧。问题3一个父物体被SetActive(false)其子物体上的动画也重置了即使子物体有自己的状态保存脚本根源父物体禁用所有子物体在层级上都会变为非激活状态它们的OnDisable也会被调用。但如果你在子物体的OnDisable中保存状态这个保存操作是有效的。技巧关键在于恢复。父物体激活后子物体会依次触发OnEnable。确保子物体的状态恢复脚本在OnEnable中并延迟一帧执行恢复操作。子物体的恢复不依赖于父物体脚本的执行顺序。问题4在移动平台如iOS/Android上使用transform.localScale Vector3.zero隐藏物体偶尔会出现物体闪烁一下再消失排查这可能与渲染线程和逻辑线程的同步有关。缩放为0的物体在某些情况下仍可能被渲染一帧。解决对于需要极致表现的情况优先采用Renderer.enabled false。如果必须用缩放可以尝试在修改缩放的同一帧也将其移出摄像机远裁剪面之外作为双保险。问题5对象池中的物体恢复状态后动画播放没问题但声音AudioSource也一起恢复了如何避免思路状态保存脚本只应关注动画状态。对于AudioSource、粒子系统ParticleSystem等其他需要独立控制的组件应在对象禁用时单独停止启用时根据情况重新播放。建议设计一个统一的OnEnterPool入池和OnSpawnFromPool出池接口让物体上不同的组件分别管理自己的重置逻辑。动画组件恢复状态音频组件停止播放并重置时间粒子组件停止并清理这样各司其职逻辑清晰。

相关新闻

Mind+图形化编程驱动Micro:bit控制LED点阵屏:从SPI通信到动态显示

Mind+图形化编程驱动Micro:bit控制LED点阵屏:从SPI通信到动态显示

1. 项目概述:当Micro:bit遇上Mind,点亮点阵屏的无限可能如果你手头有一块Micro:bit,又恰好对Mind图形化编程感兴趣,那么“点亮点阵屏”这个项目绝对是一个能让你快速获得成就感,同时又能深入理解硬件交互原理的绝佳起点…

2026/10/18 1:30:13 阅读更多 →
深度解析Playwright MCP分布式录制架构的5大设计原则

深度解析Playwright MCP分布式录制架构的5大设计原则

深度解析Playwright MCP分布式录制架构的5大设计原则 【免费下载链接】mcp-playwright Playwright Model Context Protocol Server - Tool to automate Browsers and APIs in Claude Desktop, Cline, Cursor IDE and More 🔌 项目地址: https://gitcode.com/gh_mi…

2026/10/18 22:50:41 阅读更多 →
Android设备认证修复终极指南:让银行应用不再闪退

Android设备认证修复终极指南:让银行应用不再闪退

Android设备认证修复终极指南:让银行应用不再闪退 【免费下载链接】PlayIntegrityFix Fix Play Integrity (and SafetyNet) verdicts. 项目地址: https://gitcode.com/GitHub_Trending/pl/PlayIntegrityFix 你是否遇到过这样的尴尬场景:打开银行A…

2026/10/17 8:11:29 阅读更多 →

最新新闻

新华DCS组态文件与工程师手册深度解析指南

新华DCS组态文件与工程师手册深度解析指南

简介:本资源为新华DCS系统核心工程资料包,面向工业自动化领域初/中级系统工程师、DCS运维人员及高校控制类专业实践学习者,聚焦系统组态实施与现场调试能力提升。资源包含1份HTML格式的下载说明页(含返币规则与使用提示&#xff0…

2026/10/19 0:51:08 阅读更多 →
UCIe 2.0系统架构深度解析:从芯粒互连到多die管理机制

UCIe 2.0系统架构深度解析:从芯粒互连到多die管理机制

UCIe 2.0规范发布之后,我翻得最多的章节其实是系统架构,而不是物理层波形或者链路层的CRC细节。原因很简单:1.0版本可以用“多芯片串在一起的高速接口标准”来理解,但到2.0,UCIe已经变成一套能管理、能配置、能安全启动…

2026/10/19 0:51:08 阅读更多 →
网管系统交付必读:概述文档、北向接口与告警管理实战指南

网管系统交付必读:概述文档、北向接口与告警管理实战指南

简介:《NCE-T网管操作系统概述》是一份面向华为传送网/微波网管方向的技术文档,适合网络运维工程师、系统集成人员以及对5G承载、网络自动化和智能运维感兴趣的读者。内容围绕NCE-T与U2000的架构对比展开,说明NCE-T如何继承原有管理域与NBI接…

2026/10/19 0:51:07 阅读更多 →
MATLAB与OpenDSS输配电联合仿真:有载调压与馈线调节器协同案例

MATLAB与OpenDSS输配电联合仿真:有载调压与馈线调节器协同案例

简介:这套基于MATLAB与OpenDSS开发的输配电系统联合仿真平台,面向计算机、电子信息工程及数学等专业学生的课程设计、期末大作业与毕业设计,也适合电力领域初学者作为入门工具。平台支持MATLAB 2014、2019a及2024a等多个版本,借助…

2026/10/19 0:50:07 阅读更多 →
大规模MIMO信号检测器MATLAB实战对比:MMSE/TASER/LAMA/ADMIN/KBEST

大规模MIMO信号检测器MATLAB实战对比:MMSE/TASER/LAMA/ADMIN/KBEST

简介:本资源是一套面向通信工程专业学生、科研人员及MATLAB算法开发者的大型MIMO系统信号检测算法仿真代码包,聚焦于解决高维信道下低复杂度、高性能信号恢复这一核心问题。压缩包共22个文件,以20个MATLAB函数(.m)为主…

2026/10/19 0:49:07 阅读更多 →
Win10下Charles抓包实战:从解密HTTPS到手机App调试

Win10下Charles抓包实战:从解密HTTPS到手机App调试

实习第一天,带我的导师丢过来一句话:“把电脑收拾利索,把Charles装上,等会儿联调要抓包看登录接口。”我那时候以为Charles是个什么前端框架,等装完打开才发现,它就是一台架在本机上的HTTP代理服务器&#…

2026/10/19 0:49:07 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →