Cocos Creator按钮交互进阶:从基础组件到沉浸式游戏体验
1. 项目概述从“能点”到“好玩”的交互跃迁在Cocos Creator里做游戏UI交互是玩家感知最直接的部分。很多开发者尤其是刚入门的同学常常觉得Button按钮组件太简单了——拖个节点挂上组件绑定个点击事件完事。但如果你做的游戏里按钮只是“啪”一下变个色或者弹出一个毫无反馈的界面玩家的沉浸感会瞬间断裂。这就像你去按一个真实的电梯按钮如果它既没有“咔哒”的触感反馈也没有指示灯亮起你肯定会怀疑自己到底按没按到。今天要聊的就是如何把Cocos Creator里这个最基础的Button组件从“能用”变成“好用”再从“好用”升级到“惊艳”最终为你的游戏打造出真正沉浸式的交互体验。这不仅仅是改改颜色、换换图片而是深入到交互设计的逻辑层、表现层和反馈层让每一次点击都成为游戏叙事和情感传递的一部分。无论是RPG里的关键抉择、动作游戏里的连招触发还是休闲游戏中的趣味反馈一个精心打磨的Button能极大提升游戏的整体质感和玩家留存。2. 核心设计思路构建多层次反馈系统一个沉浸式的按钮交互绝不是一个onClick事件就能概括的。我们需要建立一个从视觉、听觉到操作逻辑的完整反馈链条。这个链条可以分解为四个核心层次2.1 状态驱动的视觉反馈这是最基础也是最重要的一层。Cocos Creator的Button组件内置了四种状态Normal, Hover, Pressed, Disabled但很多人只是简单设置一下颜色。进阶用法在于利用好Sprite Transition和Scale Transition。Sprite Transition精灵切换这是实现高品质按钮的利器。不要只满足于颜色变化为每种状态准备不同的精灵图SpriteFrame。比如Normal状态是完整的金属边框Pressed状态是边框内凹并有高光Hover状态边框微微发光。这种基于材质和造型的变化比单纯变色带来的质感提升不止一个档次。Scale Transition缩放过渡这是增加“按压感”的关键。将zoomScale设置为一个略小于1的值如0.95配合一个极短的Duration如0.05秒在点击瞬间按钮会有一个轻微的“按下”动画。这里有个细节zoomScale是乘数基于节点原始缩放值。如果你的按钮原始缩放不是1需要计算好最终效果。我通常建议保持按钮原始缩放为1方便统一控制。2.2 时间与节奏控制交互是有节奏的。所有状态切换的Duration持续时间参数就是控制这个节奏的节拍器。按下Pressed到抬起Normal这个持续时间要短通常0.05s-0.1s模拟快速的物理反馈。悬停Hover进入与退出这个可以稍慢0.1s-0.2s让光标滑过时有一种“吸附”或“聚焦”的柔和感避免生硬。禁用Disabled状态切换到禁用状态时可以有一个稍慢的褪色动画如0.3秒暗示功能不可用而恢复可用时动画可以更快制造一种“解锁”的爽快感。2.3 超越视觉的复合反馈视觉之外听觉和触觉在支持震动的平台上是沉浸感的倍增器。音频反馈为Click事件绑定一个简短的音效。注意音效应与按钮的视觉风格和游戏整体音效协调。一个水晶按钮配“叮”的一声一个重盾按钮配“咚”的闷响。避免所有按钮都用同一个音效会产生疲劳。逻辑反馈点击后在触发核心业务逻辑如打开面板之前可以插入一个极短的延迟如0.1秒用于播放一个完整的点击动画比如按钮光圈扩散、粒子特效迸发。这能让玩家明确感知到“操作已生效”即使后续加载有卡顿也不会觉得是没点上。2.4 可交互性Interactable的动态管理Interactable属性不能只是静态的true/false。它应该是一个动态的游戏状态接口。冷却时间CD技能按钮释放后立即将Interactable设为false同时启动一个进度条ProgressBar或遮罩动画来可视化冷却过程。冷却结束时不仅恢复为true最好配合一个轻微的闪光或缩放动画提示玩家“技能就绪”。条件锁定当玩家金币不足时购买按钮应变为Disabled状态并可以结合一个红色的“-10”飘字动画直观告知原因。这比弹出一个提示框更流畅。3. 实战进阶打造三类高沉浸感按钮理解了设计思路我们通过三个具体案例来看看如何组合运用这些技术。3.1 案例一动态技能按钮这是一个典型的、包含冷却、状态反馈和特效的按钮。步骤实现节点与组件准备创建一个空节点SkillButton。添加Sprite组件放入技能图标作为背景。添加Button组件。在Transition类型中选择SPRITE。Normal State: 正常技能图标。Pressed State: 图标变暗或增加一个“按下”效果的边框图。Hover State: 图标周围增加一圈微弱的发光图。Disabled State: 一个灰色的、带有“禁用”斜线或锁形图标的SpriteFrame。在SkillButton下创建一个子节点CDMask添加Sprite组件使用一个从中心向四周扩散的环形遮罩材质并初始设置为fillTypeRADIALfillRange0完全填充。将其颜色设为半透明黑色。脚本逻辑实现TypeScriptimport { _decorator, Component, Button, Sprite, UITransform, tween, Vec3 } from cc; const { ccclass, property } _decorator; ccclass(SkillButton) export class SkillButton extends Component { property(Button) button: Button null!; property(Sprite) cdMaskSprite: Sprite null!; private _isCooling: boolean false; private _coolDownTime: number 2.0; // 冷却2秒 start() { this.cdMaskSprite.fillRange 0; // 初始无冷却遮罩 // 监听按钮点击事件 this.button.node.on(Button.EventType.CLICK, this.onSkillClick, this); } onSkillClick() { if (this._isCooling) return; // 1. 立即进入冷却状态 this._isCooling true; this.button.interactable false; // 2. 播放点击特效这里假设有一个粒子子节点 this.playClickEffect(); // 3. 执行技能逻辑 this.castSkill(); // 4. 开始冷却动画 this.cdMaskSprite.fillRange 1; // 满遮罩 tween(this.cdMaskSprite) .to(this._coolDownTime, { fillRange: 0 }) // 2秒内填充范围从1减到0 .call(() { // 冷却结束 this._isCooling false; this.button.interactable true; // 可添加一个“冷却完毕”的闪烁提示 this.playReadyEffect(); }) .start(); } playClickEffect() { // 触发粒子系统或帧动画 console.log(播放技能释放特效); } castSkill() { // 实际的技能施放逻辑 console.log(释放技能); } playReadyEffect() { // 冷却完毕的提示效果例如快速闪烁两次 tween(this.button.node) .to(0.1, { scale: new Vec3(1.1, 1.1, 1) }) .to(0.1, { scale: new Vec3(1, 1, 1) }) .start(); } }关键点解析这里用Sprite的fillRange属性来实现环形冷却遮罩比用ProgressBar组件更灵活可以匹配任意形状的技能图标。冷却状态与interactable强绑定并提供了视觉遮罩和终末闪烁的双重反馈。3.2 案例二自适应长按按钮蓄力/连续操作某些游戏需要长按按钮例如蓄力攻击、连续加速。原生Button组件不支持长按检测我们需要自己扩展。步骤实现节点准备同上创建一个带Button和Sprite的按钮节点。额外添加一个ProgressBar组件或一个横向拉伸的Sprite作为蓄力进度条默认隐藏。脚本逻辑实现import { _decorator, Component, Button, ProgressBar, input, Input, EventTouch, tween, Vec3 } from cc; const { ccclass, property } _decorator; ccclass(HoldButton) export class HoldButton extends Component { property(Button) button: Button null!; property(ProgressBar) powerBar: ProgressBar null!; private _isHolding: boolean false; private _holdTimer: number 0; private _maxHoldTime: number 1.5; // 最大蓄力1.5秒 start() { this.powerBar.node.active false; // 监听触摸开始和结束 this.button.node.on(Input.EventType.TOUCH_START, this.onTouchStart, this); this.button.node.on(Input.EventType.TOUCH_END, this.onTouchEnd, this); this.button.node.on(Input.EventType.TOUCH_CANCEL, this.onTouchEnd, this); // 触摸取消也视为结束 } onTouchStart(event: EventTouch) { this._isHolding true; this._holdTimer 0; this.powerBar.node.active true; this.powerBar.progress 0; // 可以改变按钮外观提示进入蓄力模式 // this.button.getComponent(Sprite)?.color new Color(255, 150, 150); } update(deltaTime: number) { if (!this._isHolding) return; this._holdTimer deltaTime; let progress Math.min(this._holdTimer / this._maxHoldTime, 1.0); this.powerBar.progress progress; // 蓄力过程中的视觉反馈例如根据进度改变颜色 // if (progress 0.8) { this.powerBar.barSprite.color Color.RED; } } onTouchEnd(event: EventTouch) { if (!this._isHolding) return; this._isHolding false; let holdProgress this.powerBar.progress; this.powerBar.node.active false; // 根据蓄力进度执行不同效果 this.executeHoldAction(holdProgress); // 恢复按钮外观 // this.button.getComponent(Sprite)?.color Color.WHITE; } executeHoldAction(progress: number) { if (progress 0.3) { // 短按轻攻击 console.log(轻攻击); } else if (progress 0.8) { // 中等蓄力重攻击 console.log(重攻击); } else { // 满蓄力特殊攻击 console.log(必杀技); } } }关键点解析我们绕过了Button的CLICK事件直接监听TOUCH_START和TOUCH_END从而获得更底层的触摸控制权。在update函数中更新蓄力进度这是游戏循环的典型应用。注意性能确保在非蓄力状态时相关逻辑不被执行。TOUCH_CANCEL事件必须处理当触摸点滑出按钮区域或被系统事件打断时它会触发我们需要在此情况下也结束蓄力。3.3 案例三带动态效果的菜单按钮用于主界面、暂停菜单强调美感和连贯性。步骤实现效果设计悬停效果不仅切换图片可以增加一个图标轻微上下浮动的动画。点击效果点击后按钮可能伴随一个“缩小-放大”的弹性动画并飞溅出几个小粒子。连带动画点击按钮打开一个新面板时按钮本身可以作为一个“发射点”引导玩家的视线移动到新面板出现的位置。脚本逻辑示例悬停浮动import { _decorator, Component, Button, tween, Vec3 } from cc; const { ccclass, property } _decorator; ccclass(MenuButton) export class MenuButton extends Component { property(Button) button: Button null!; private _originalPos: Vec3 new Vec3(); private _hoverTween: any null; start() { this._originalPos this.node.position.clone(); // 监听鼠标移入移出Web/PC平台 this.button.node.on(Node.EventType.MOUSE_ENTER, this.onMouseEnter, this); this.button.node.on(Node.EventType.MOUSE_LEAVE, this.onMouseLeave, this); } onMouseEnter() { // 停止之前的动画 if (this._hoverTween) this._hoverTween.stop(); // 创建浮动动画 this._hoverTween tween(this.node) .by(0.5, { position: new Vec3(0, 5, 0) }, { easing: sineInOut }) .by(0.5, { position: new Vec3(0, -5, 0) }, { easing: sineInOut }) .union() // 将两个动画合并 .repeatForever() // 永久重复 .start(); } onMouseLeave() { if (this._hoverTween) { this._hoverTween.stop(); this._hoverTween null; } // 平滑回到原位 tween(this.node) .to(0.2, { position: this._originalPos }) .start(); } }关键点解析使用tween系统创建连续、可循环的动画让悬停效果更生动。union()方法可以将多个动画序列合并方便创建复杂的组合动画。在鼠标移出时一定要停止循环动画并使用一个短暂的补间回到原位避免画面跳变。4. 性能优化与最佳实践当界面中按钮数量众多时如背包、技能栏性能问题不容忽视。4.1 合批与渲染优化使用相同的图集确保所有按钮的默认、按下、悬停状态所使用的SpriteFrame都来自同一张纹理图集。这是UI合批Static Batching的前提能极大减少Draw Call。慎用Scale Transition缩放变换会破坏UI的合批。如果必须使用尽量让这些按钮在层级上靠近或者考虑使用UIMeshRenderer进行自定义合批进阶内容。UIStaticBatch组件对于完全静态的按钮组如主菜单可以尝试使用UIStaticBatch组件进行静态合批但要注意被合批的节点及其子节点将无法再进行任何变换动画。4.2 事件管理及时销毁监听在按钮所在的节点销毁例如关闭界面时务必移除所有事件监听防止内存泄漏。onDestroy() { this.button.node.off(Button.EventType.CLICK, this.callback, this); // 移除自定义的触摸监听 input.off(Input.EventType.TOUCH_START, this.onTouchStart, this); // ... 移除其他监听 }使用EventHandler对象池如果需要在运行时动态创建大量按钮并绑定事件频繁创建new EventHandler()可能引发GC垃圾回收压力。可以预先创建一个EventHandler对象池进行复用。4.3 适配与布局Widget组件是关键确保你的按钮节点上正确使用了Widget对齐挂件组件并设置好与父节点的边距或对齐方式。这是实现多分辨率适配的基础能让按钮在不同屏幕上始终处于正确的位置。点击区域优化对于不规则形状的按钮其点击区域默认是节点矩形包围盒。如果图形镂空较多可能导致误触或点不到。可以通过添加一个透明的Sprite子节点来扩大点击区域或者使用Graphics组件绘制一个更贴合形状的碰撞区域需配合自定义射线检测较复杂。5. 常见问题与排查技巧实录在实际开发中你肯定会遇到各种关于Button的“坑”。这里记录几个典型问题和我的解决思路。问题1按钮点击没反应但控制台没报错。排查步骤检查节点层级确认按钮节点没有被一个设置了BlockInputEvents组件的节点覆盖。这个组件会拦截所有输入事件。检查Interactable和Enabled确保Button组件的Interactable为true并且节点本身的active属性也为true。检查尺寸和位置按钮的UITransform尺寸是否为0或者位置是否远远超出了屏幕范围检查事件绑定如果是代码绑定确认回调函数名是否拼写正确函数是否为公共方法或已正确声明。查看渲染顺序如果按钮的zIndex很低被其他元素完全遮住也可能无法点击。检查Canvas下节点的渲染顺序。问题2按钮的状态切换如Hover在移动设备上不生效。原因与解决MOUSE_ENTER和MOUSE_LEAVE是桌面端鼠标事件。在移动设备上没有“悬停”概念。Button组件自身的Hover状态在移动端是通过“触摸开始但未松开”来模拟的即长按但未抬起。如果你的自定义悬停逻辑依赖于鼠标事件需要在移动端用TOUCH_START和TOUCH_END来模拟或者直接使用Button组件自带的Transition状态它是跨平台工作的。问题3动态创建的按钮绑定事件后点击无效。原因很可能是在节点激活active true之前就绑定了事件。Cocos Creator中某些组件包括事件系统在节点非激活状态下初始化可能不完整。解决确保在节点activeInHierarchy为true之后再执行事件绑定操作。通常放在onEnable或start生命周期里是安全的。如果必须动态创建并立即绑定可以在调用addChild之后手动调用一次新节点的active true如果它还没激活的话。问题4按钮点击时同时触发了底层节点的触摸事件如滚动视图。原因触摸事件存在“冒泡”机制。点击按钮时事件也会传递给它的父节点。解决在按钮的事件回调函数中调用event.propagationStopped true;来停止事件继续向上冒泡。callback(event: EventTouch) { // 你的按钮逻辑... event.propagationStopped true; // 阻止事件冒泡避免触发父容器滚动等 }问题5Scale Transition导致按钮在点击时位置发生偏移。原因缩放是以节点的锚点Anchor为中心进行的。如果锚点不是(0.5, 0.5)缩放时节点就会“跑偏”。解决将按钮节点的锚点Anchor设置为(0.5, 0.5)这样缩放就会以其中心点进行位置不会改变。这是UI按钮的通用最佳实践。最后我个人的一个强烈建议是为你的项目建立一套按钮交互规范。定义好不同类型按钮主按钮、次要按钮、危险操作按钮、图标按钮等的标准状态Normal, Hover, Pressed, Disabled样式、过渡时间、音效、甚至震动力度。在游戏开发的早期就确定这些规范并封装成几个预制的Prefab预制体或基础组件能让整个游戏的UI体验迅速统一并提升到专业水准。记住好的交互是“无感”的玩家不会特意称赞一个按钮多好按但一个糟糕的按钮会立刻被注意到并破坏游戏体验。

相关新闻

二叉搜索树操作精解:修剪、构建与累加转换

二叉搜索树操作精解:修剪、构建与累加转换

1. 二叉搜索树基础与LeetCode刷题策略 二叉搜索树(BST)作为数据结构中的常青树,在算法面试中出现的频率居高不下。今天我们就来深度剖析LeetCode中三道典型的BST题目:669(修剪)、108(构建&#…

2026/10/18 10:49:37 阅读更多 →
RAG系统知识库增量更新实战:基于LangChain Indexing API的生产级解决方案

RAG系统知识库增量更新实战:基于LangChain Indexing API的生产级解决方案

1. 项目概述:为什么知识库的“保鲜”是个技术活做RAG(检索增强生成)系统的朋友,尤其是那些已经将系统投入生产环境的朋友,一定都遇到过这个头疼的问题:昨天刚上传的公司最新产品手册,今天AI客服…

2026/10/16 13:34:50 阅读更多 →
AI漫剧提示词工程化指南:从构思到精准生成

AI漫剧提示词工程化指南:从构思到精准生成

你是不是也遇到过这种情况:想用AI生成一部精彩的漫剧,脑子里画面感十足,但写出来的提示词(Prompt)却让AI一头雾水,生成的结果要么平淡无奇,要么完全跑偏?比如,你输入“一…

2026/10/16 13:35:23 阅读更多 →

最新新闻

OpenRT实战:多模态大模型红队安全评估从入门到落地

OpenRT实战:多模态大模型红队安全评估从入门到落地

如果你最近在盯多模态大模型的安全测评,大概已经听过OpenRT这个名字——一个开源的LLM红队框架,主打对多模态模型做系统化的健壮性评估。前阵子我正好把它用在一个客服问答系统的上线前检查里,发现很多人对它的理解还停留在“又一个提权工具”…

2026/10/18 10:48:51 阅读更多 →
Oracle 12c Windows补丁升级避坑指南:OPatch版本、JDK兼容与路径陷阱

Oracle 12c Windows补丁升级避坑指南:OPatch版本、JDK兼容与路径陷阱

简介:本资源是专为Windows平台Oracle 12c数据库环境定制的OPatch补丁管理工具集,面向DBA、运维工程师及数据库开发人员,用于安全、高效地应用Oracle官方补丁(如PSU、BP、One-Off等),解决补丁部署失败、OPat…

2026/10/18 10:48:51 阅读更多 →
ODAC122010Xcopy-x64.zip:.NET Framework 4.x 免注册 Oracle 数据访问方案

ODAC122010Xcopy-x64.zip:.NET Framework 4.x 免注册 Oracle 数据访问方案

简介:本资源是Oracle官方ODAC(Oracle Data Access Components)12.2.0.1.0版本的64位完整离线安装包,专为Windows平台下.NET开发者设计,适用于ASP.NET Web应用、桌面程序及企业级事务系统开发,解决.NET项目连…

2026/10/18 10:48:51 阅读更多 →
OPC UA Python客户端实战:Linux边缘设备稳定连接PLC指南

OPC UA Python客户端实战:Linux边缘设备稳定连接PLC指南

简介:本资源为一套经过实际测试验证的OPC UA客户端完整实现工程,面向工业自动化领域开发者、物联网系统集成工程师及学习工业通信协议的中高级技术人员,解决OPC UA客户端开发入门难、安全连接配置复杂、服务调用逻辑不清晰等实践痛点。压缩包…

2026/10/18 10:48:51 阅读更多 →
Java Swing黄金矿工实战:抛物线动画与双缓冲渲染

Java Swing黄金矿工实战:抛物线动画与双缓冲渲染

简介:本资源是基于Java语言实现的经典休闲游戏《黄金矿工》的完整可运行项目,面向Java初学者与GUI编程进阶学习者,帮助掌握面向对象设计、Swing图形界面开发、事件驱动机制及基础游戏逻辑实现等核心能力。压缩包共30个文件,包含6个…

2026/10/18 10:48:51 阅读更多 →
PFA算法:基于正交投影一致性的多模态特征空间隐式对齐

PFA算法:基于正交投影一致性的多模态特征空间隐式对齐

简介:本资源为数据挖掘领域Pattern Fusion(PFA)算法的完整实践套件,面向算法研究者、R/ MATLAB开发者及高年级本科生或研究生,聚焦于大规模频繁模式的精炼提取与融合优化问题。资源共23个文件,涵盖9个txt&a…

2026/10/18 10:47:51 阅读更多 →

日新闻

基于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 阅读更多 →

周新闻

基于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/16 14:23:36 阅读更多 →