news 2026/10/12 1:21:08

Uniswap interface 仓库的 argent-device-interact 技能指南:iOS 模拟器与 Android 模拟器统一设备交互实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Uniswap interface 仓库的 argent-device-interact 技能指南:iOS 模拟器与 Android 模拟器统一设备交互实战
  • 区块链
  • DeFi
  • 前端
  • 移动开发

【免费下载链接】interface

🦄 Open source interfaces for the Uniswap protocol

项目地址:https://gitcode.com/gh_mirrors/in/interface
点击查看免费下载

本篇技术指南面向在 Uniswap interface 单仓库中开发与调试移动端(apps/mobile)的 AI Agent 与开发者,系统讲解.agents/skills/argent-device-interact/SKILL.md所定义的统一设备交互技能:如何用同一套 MCP 工具完成点击、手势、滑动、打字、硬件按键、启动应用、打开 URL 与截图,并由工具服务器根据udid形态自动分派到 iOS 模拟器或 Android 模拟器。读完本文,你将掌握完整的工具选型矩阵、归一化坐标体系、目标发现策略(describe家族)、多步动作序列化(run-sequence)以及 Android 平台专属坑点(Metroadb reverse、锁屏、权限预授权),并能直接在本仓库的移动端工程上落地执行。

1. 技能定位与统一工具表面(udid 自动分派)

argent-device-interact是 Uniswap interface 仓库 .agents/skills 目录下的一套 Agent 技能(skill),其核心设计是统一工具表面(Unified tool surface):

  • 所有交互工具都接受一个udid参数;
  • 工具服务器根据udid的形态自动分派平台:UUID 形态(如A1B2C3D4-E5F6-7890-ABCD-EF1234567890)→ iOS 模拟器;其他任何值(如emulator-5554这样的 adb serial)→ Android 模拟器/真机;
  • 因此 iOS 与 Android 使用完全相同的工具名:gesture-tap、gesture-swipe、describe、screenshot、launch-app、keyboard等。

平台专属注意事项(Metroadb reverse、锁屏时describe报错等)集中在原文档第 9 节,即本文第 10 章。

这套技能的配套生态还包括 argent-ios-simulator-setup(模拟器启动与连接)、argent-android-emulator-setup(AVD 启动与 adb 前置条件)、argent-metro-debugger(Metro CDP 调试)与 argent-test-ui-flow(交互-截图-验证循环),它们共同构成在 apps/mobile 这类 React Native 工程上的完整 Agent 端开发调试工作流。

2. 开始之前:设备发现、启动与工具 schema 预加载

2.1 委托子 Agent 前确认 MCP 权限

如果要把模拟器任务委托给子 Agent,务必确保子 Agent 具备 MCP 权限,否则交互工具不可用。

2.2 用 list-devices 获取目标设备

  • 调用list-devices获取目标 id,结果带platform标签(ios或android),已启动/就绪的设备排在前面;
  • 选择第一个匹配所需平台的条目即可;
  • 如果没有任何就绪设备,调用boot-device:iOS 传udid,Android 传avdName。

完整的启动流程分别见 argent-ios-simulator-setup(iOS 侧:list-devices过滤platform: "ios",无就绪设备则boot-device传 UDID)与 argent-android-emulator-setup(Android 侧:需要 PATH 上有adb与emulator,通过adb version与emulator -list-avds验证,就绪设备state: "device"排在前面,无就绪设备则按avds列表中的名字调用boot-device)。

2.3 首次使用前务必加载工具 schema

手势工具(gesture-tap、gesture-swipe、gesture-pinch、gesture-rotate、gesture-custom)的 schema 可能采用延迟加载——它们的参数 schema 在主动获取前并未加载。因此在调用任何手势工具之前,必须先用 ToolSearch 加载所有计划使用的手势工具 schema。如果跳过这一步,参数可能被强制转换为字符串而不是数字,从而引发校验错误(validation errors)。

3. 最佳实践清单

原文档第 2 节给出了六条核心实践原则,直接决定交互的可靠性与效率:

  1. 点击前必查 tapping_rule:始终参考argent.md规则文件中的tapping_rule再执行点击。
  2. 优先考虑顺序分派:执行交互前,先判断动作是否可以拆成多步序列一次性下发,更多细节见第 9 章run-sequence。
  3. 列表滚动用gesture-swipe而非gesture-custom:除非需要非线性移动;如果需要多次滑动,优先使用run-sequence批处理。
  4. 输入文本前先点击文本框:iOS 上先尝试paste,失败再回退keyboard;Android 直接使用keyboard(paste仅限 iOS)。
  5. 坐标一律归一化:始终使用 0.0–1.0 的归一化坐标,而不是像素。
  6. 原生 iOS 应用导航优先describe:describe无需重启应用即可在任何界面工作;常规应用内页面不要靠截图来导航,除非describe无法暴露可靠目标;只有需要应用级 UIKit 属性时才使用native-describe-screen。

4. 打开应用:launch-app 与 open-url

核心规则:永远不要通过点击桌面图标来导航到应用。使用launch-app或open-url,它们瞬时且可靠。

launch-app — 按 bundle ID 启动

{ "udid": "<UDID>", "bundleId": "com.apple.MobileSMS" }

常用 bundle ID:

应用bundleId
信息(Messages)com.apple.MobileSMS
Safaricom.apple.mobilesafari
设置(Settings)com.apple.Preferences
地图com.apple.Maps
照片com.apple.Photos
邮件com.apple.mobilemail
备忘录com.apple.mobilenotes
通讯录com.apple.MobileAddressBook

open-url — 按 URL scheme 打开

{ "udid": "<UDID>", "url": "messages://" }

常用 scheme:messages://、settings://、maps://?q=<query>、tel://<number>、mailto:<address>、https://...(在 Safari 中打开)。

对于本仓库的 React Native 移动端应用,launch-app接受 UDID/设备 id 与 bundle ID(iOS)或包名(Android),参见 argent-react-native-app-workflow 第 3.5 节设备控制表;open-url还承担 deep link 测试职责,例如验证钱包连接、兑换页等业务深链,这一点在 argent-create-flow 中被反复强调——深链比点击序列对布局变化更鲁棒。

5. 工具选择速查表

原文档第 4 节提供了一张完整的“动作 → 工具”映射表,这是任何交互任务的第一步决策依据:

动作工具说明
多个动作run-sequence一次调用批量执行步骤(无中间截图)
打开应用launch-app总是用它——绝不点击桌面图标
重启应用restart-app按 bundle ID 终止并重新启动
打开 URL/schemeopen-url网页、deep link、URL scheme
单击gesture-tap按钮、链接、复选框
滚动/滑动gesture-swipe直线滚动或滑动
长按gesture-custom上下文菜单、拖拽起点
拖放gesture-custom复杂拖拽交互
捏合/缩放gesture-pinch双指捏合,自动插值
旋转gesture-rotate双指旋转,自动插值
自定义手势gesture-custom任意触摸序列,可选插值
硬件按键buttonhome、back、power、volume、appSwitch、actionButton
快速输入文本paste仅 iOS。表单字段——使用剪贴板
输入文本keyboardiOS+Android。paste 失败时的回退;支持 Enter、Escape、方向键
旋转设备rotate改变屏幕方向

6. 发现点击目标:describe 家族与备选策略

核心规则:当动作执行后切换到不同屏幕、或不知道组件坐标时,务必先做正式的目标发现(discovery),不要凭截图盲猜。

6.1 发现工具矩阵

应用类型发现工具返回内容
目标应用通用发现describe当前设备屏幕的可访问性元素树(iOS AX-service 或 Android uiautomator),带归一化 frame 坐标。适用于任意应用、系统对话框与主屏幕——无需应用重启,也无需bundleId
React Nativedebugger-component-treeReact 组件树,含名称、文本、testID 与(tap: x,y)坐标
应用级原生native-describe-screen应用级可访问性元素的低层视图,含归一化与原始坐标;需要bundleId
权限/系统模态浮层describedescribe会自动检测系统对话框并返回带点击坐标的对话框按钮;只有describe无法暴露控件时才回退screenshot
最终视觉回退screenshot仅当发现工具无法可靠检查当前 UI 时使用;不要从截图中推导常规应用内导航目标

在已经获得候选坐标点之后,如果需要进一步的原生诊断,可使用两个点位级工具:

  • native-user-interactable-view-at-point:已知原始 iOS 坐标点上、实际会接收触摸的最深原生视图;需要bundleId;
  • native-view-at-point:已知原始 iOS 坐标点上、视觉上最深的原生视图;需要bundleId。

两者的区别在于前者是 hit-test 命中目标,后者是视觉最深层视图。

对于 React Native 应用,argent-metro-debugger 进一步补充:debugger-component-tree用于“屏幕上有什么、在哪里”的布局总览与点击目标发现;debugger-inspect-element则用逻辑像素坐标(注意:不是归一化 0–1)在 (x, y) 处定位组件,并回溯源文件文件:行号与代码片段——适用于“这个组件是什么、在哪里定义的”。在 Android 上使用这些调试器工具前,必须先执行adb -s <serial> reverse tcp:8081 tcp:8081让设备能访问宿主机上的 Metro。

6.2 describe 失败时的诊断路径

原文档要求:读精确的错误信息,然后选择与之匹配的动作:

  • 错误提及ax-service不可用或 daemon 启动失败:ax-service daemon 无法启动,检查模拟器是否已启动。临时回退用screenshot;若应用注入了原生 devtools,也可用带显式bundleId的native-describe-screen。
  • describe返回空元素列表:屏幕可能空白、正在加载、或显示无可访问性标签的内容。用screenshot查看可见内容,内容加载后重试。
  • describe成功但对 React Native 应用不够详细:改用debugger-component-tree。
  • 需要带完整 UIKit 属性(accessibilityIdentifier、viewClassName)的应用级检查:用带显式bundleId的native-describe-screen。这需要原生 devtools(dylib)注入——必要时先调用restart-app。
  • 已有候选坐标点、想确认实际会接收触摸的视图:用native-user-interactable-view-at-point;想看视觉最深层视图则用native-view-at-point。

7. 手势与输入工具详解

所有手势工具的坐标、距离、半径均为归一化 0.0–1.0(屏幕宽/高的比例,而非像素),这是全家族统一的空间约定,参考文件 references/gesture-examples.md 同样强调这一点。

7.1 gesture-tap — 单点单击

{ "udid": "<UDID>", "x": 0.5, "y": 0.5 }

坐标约定:0.0= 左/上,1.0= 右/下。

RN 应用特例:在 React Native 应用中点击屏幕底部附近之前,先检查是否有 “Open Debugger to View Warnings” 横幅可见——点击它会断开调试器连接。若存在,先用 X 图标关闭。

7.2 gesture-swipe — 直线手势

{ "udid": "<UDID>", "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 }

方向语义:向上滑(fromY > toY)= 内容向下滚动。默认时长 300ms;可选"durationMs": 500放慢速度。

7.3 gesture-pinch — 双指捏合

{ "udid": "<UDID>", "centerX": 0.5, "centerY": 0.5, "startDistance": 0.2, "endDistance": 0.6 }

所有值均为归一化 0.0–1.0(屏幕比例,非像素),与所有手势工具一致。startDistance: 0.2表示双指起始相距屏幕的 20%,endDistance: 0.6表示结束时相距 60%。方向语义:startDistance < endDistance= 捏合展开(放大 zoom in);startDistance > endDistance= 捏合收拢(缩小 zoom out)。默认值:angle: 0(水平轴)、durationMs: 300;可选"angle": 90切换垂直轴、"durationMs": 500放慢速度。

references/gesture-examples.md 补充了纵向捏合示例:angle: 90时使用相同的startDistance/endDistance语义。

7.4 gesture-rotate — 双指旋转

{ "udid": "<UDID>", "centerX": 0.5, "centerY": 0.5, "radius": 0.15, "startAngle": 0, "endAngle": 90 }

所有位置与半径均为归一化 0.0–1.0。radius: 0.15表示每根手指距中心为屏幕尺寸的 15%。方向语义:endAngle > startAngle= 顺时针。默认时长 300ms;可选"durationMs": 500放慢。逆时针 45 度示例见参考文件:startAngle: 0, endAngle: -45。

7.5 gesture-custom — 自定义触摸序列

用于长按、拖放及其它复杂序列。设置"interpolate": 10可自动在关键帧之间生成平滑的中间 Move 事件。参考文件 references/gesture-examples.md 提供了三种典型场景:

长按(800ms 保持):

{ "udid": "<UDID>", "events": [ { "type": "Down", "x": 0.5, "y": 0.5 }, { "type": "Up", "x": 0.5, "y": 0.5, "delayMs": 800 } ] }

手动 pinch out(无插值):

{ "udid": "<UDID>", "events": [ { "type": "Down", "x": 0.4, "y": 0.5, "x2": 0.6, "y2": 0.5 }, { "type": "Move", "x": 0.2, "y": 0.5, "x2": 0.8, "y2": 0.5 }, { "type": "Up", "x": 0.2, "y": 0.5, "x2": 0.8, "y2": 0.5 } ] }

带插值的平滑 pinch out(interpolate: 15):

{ "udid": "<UDID>", "events": [ { "type": "Down", "x": 0.4, "y": 0.5, "x2": 0.6, "y2": 0.5 }, { "type": "Up", "x": 0.2, "y": 0.5, "x2": 0.8, "y2": 0.5 } ], "interpolate": 15 }

拖放(Drag and Drop):

{ "udid": "<UDID>", "events": [ { "type": "Down", "x": 0.3, "y": 0.4 }, { "type": "Move", "x": 0.3, "y": 0.4, "delayMs": 500 }, { "type": "Move", "x": 0.7, "y": 0.6 }, { "type": "Up", "x": 0.7, "y": 0.6 } ] }

参考文件特别提示:在第一个Move上加delayMs可以模拟拖拽前的持续按压——部分拖放实现只在持续按压激活后才响应。

7.6 button — 硬件按键

{ "udid": "<UDID>", "button": "home" }

可选值:home、back、power、volumeUp、volumeDown、appSwitch、actionButton。

7.7 paste — 向聚焦字段输入文本(仅 iOS)

{ "udid": "<UDID>", "text": "Hello, world!" }

先点击字段,再 paste;不生效时回退keyboard。在 Android 上该调用会被能力门禁拒绝(错误信息为 “Tool 'paste' is not supported on android”),应直接使用keyboard。

7.8 keyboard — 输入文本或特殊按键

{ "udid": "<UDID>", "text": "search query", "key": "enter" }

特殊按键:enter、escape、backspace、tab、space、arrow-up、arrow-down、arrow-left、arrow-right、f1–f12。可选"delayMs": 100控制按键间隔(默认 50ms)。

7.9 rotate — 改变屏幕方向

{ "udid": "<UDID>", "orientation": "LandscapeLeft" }

可选值:Portrait、LandscapeLeft、LandscapeRight、PortraitUpsideDown。

8. 截图策略与 Troubleshooting

8.1 何时使用显式 screenshot 工具

只有在以下场景才使用显式screenshot工具:

  • 需要在任何动作之前获取初始屏幕状态;
  • 自动附带的截图显示的是过渡帧或加载帧;
  • 需要额外上下文;
  • 需要在延迟后检查状态(例如等待网络响应);
  • 出现了权限对话框、系统弹窗或原生模态浮层,且describe未暴露可靠目标。

使用screenshot处理权限或原生模态导航时:

  • 不要因为看到模态框就切换到截图驱动导航——常规应用页面与应用内模态仍应使用describe;
  • 优先点击居中的明显弹窗按钮,如Allow、OK、Don't Allow、Not Now、Continue;
  • 每次只点击一个控件,并在进行下一步之前检查返回的自动截图;
  • 模态关闭后,回到describe、native-describe-screen或debugger-component-tree进行正常发现。

可选旋转参数{ "udid": "<UDID>", "rotation": "LandscapeLeft" }可以在不改变模拟器方向的情况下旋转截图。

8.2 分辨率与缩放

截图默认按原分辨率 30% 降采样以减小上下文体积。scale接受 0.01 到 1.0。若 UI 元素难以辨认或需要检查细节,传scale: 1.0获取全分辨率:

{ "udid": "<UDID>", "scale": 1.0 }

8.3 Troubleshooting 对照表

问题解决方案
截图超时通过stop-simulator-server工具重启 simulator-server
没有已启动的 iOS 模拟器用 iOSudid调用boot-device
没有就绪的 Android 设备用avdName调用boot-device

9. run-sequence:多步动作序列化

9.1 设计目标与适用场景

run-sequence将多个交互步骤批量放入一次工具调用,全部步骤完成后只返回一张截图。适用场景:

  • 多次滚动、自动输入并提交;
  • 已知的多步点击序列;
  • 来回旋转设备。

关键约束:当任何一步需要观察前一步的结果才能继续时,不要使用run-sequence。使用场景判断:

  • 已知某个动作需要多步且无需即时查看截图——“滚动到底部/顶部/滚动到 X”时连续滚动 3–5 次;
  • 表单交互——“清空并重输字段”可以用三连击全选后输入新值;
  • “提交表单”→ 按顺序填完所有字段后点击提交;
  • “返回 X”→ 定义好的导航点击序列。

9.2 允许在序列内使用的工具

gesture-tap、gesture-swipe、gesture-custom、gesture-pinch、gesture-rotate、button、keyboard、rotate。

udid是共享的——不要在每一步的args里重复包含。每步可选delayMs(默认 100ms)。

9.3 示例

连续向下滚动三次:

{ "udid": "<UDID>", "steps": [ { "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } }, { "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } }, { "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 } } ] }

向聚焦字段输入并提交:

{ "udid": "<UDID>", "steps": [ { "tool": "keyboard", "args": { "text": "hello world" } }, { "tool": "keyboard", "args": { "key": "enter" } } ] }

点击已知按钮后向下滚动(第二步行前等待 300ms):

{ "udid": "<UDID>", "steps": [ { "tool": "gesture-tap", "args": { "x": 0.5, "y": 0.15 } }, { "tool": "gesture-swipe", "args": { "fromX": 0.5, "fromY": 0.7, "toX": 0.5, "toY": 0.3 }, "delayMs": 300 } ] }

序列在首个错误处停止,并返回部分结果。

10. 平台专属注意事项:Android 与 iOS

10.1 Android

  • Metro 可达性:在 RN 应用启动前,在设备上执行adb reverse tcp:8081 tcp:8081,否则 Metro 无法从设备访问;完整工作流见 argent-metro-debugger。设备重启后需重新执行。
  • 首次启动权限弹窗:Android 上reinstall-app总是以-g安装,因此运行时权限在首次启动时已预授权,无需传额外标志(argent-android-emulator-setup 第 4 节同样确认了这一点)。
  • 锁屏/安全界面:describe在无法捕获时(keyguard、DRM、Play Integrity)会抛出明确错误;解锁设备或回退到screenshot。
  • reinstall-app的 APK 与 .app:Android 上传.apk绝对路径;iOS 上传.app目录。

10.2 iOS

原文档当前 iOS 专属坑点尚未收集(“add them as they come up”),可从 iOS 侧文档确认的基本事实包括:UDID 形态为 UUID(如A1B2C3D4-E5F6-7890-ABCD-EF1234567890);iOS 模拟器默认通过 localhost 访问同机 Metro,无需额外反向端口配置;交互工具会在未运行时自动启动服务端(argent-ios-simulator-setup)。

11. 生态联动:从交互到 UI 测试与流程回放

argent-device-interact不是孤立工具集,它与本仓库其他技能构成完整闭环:

  • argent-test-ui-flow:将交互工具嵌入“截图基线 → 发现目标 → 交互 → 截图验证”的循环中,可自动执行登录、导航等端到端 UI 场景。其核心模板为:screenshot看当前状态 → 导航/点击/输入并验证自动截图 → 执行待测动作并验证 → 报告 pass/fail。
  • argent-create-flow:把验证过的交互序列录制为.yaml流程文件(存于.argent/flows/),之后用一次flow-execute调用即可回放。录制时flow-add-step中的args必须是JSON 字符串而非对象,例如args: "{\"udid\": \"<UDID>\", \"x\": 0.5, \"y\": 0.35}"。该技能还定义了坐标漂移、元素缺失、时机、状态不匹配等故障分类与修复策略,回放失败时按“编辑 YAML → 手动恢复 → 断点重录 → 全量重录”的决策启发式处理。
  • argent-react-native-app-workflow:覆盖 Metro 启动、应用构建/安装、设备控制(list-devices、boot-device、launch-app、restart-app、open-url、rotate、stop-simulator-server)以及 release 变体验证时的陈旧代码陷阱。

12. 与 Uniswap mobile 工程的对接要点

在本仓库中,上述交互技能的服务对象主要是 apps/mobile(React Native,Expo 56 / React Native 0.85.3,见 apps/mobile/package.json)以及 apps/web 等前端应用。对接时注意:

  • 构建与启动命令优先走工程自定义脚本:argent-react-native-app-workflow 强调不要默认npx react-native start,本仓库移动端统一通过bun mobile start启动 Metro、bun mobile ios/bun mobile android运行应用(脚本定义见 apps/mobile/package.json)。
  • Android 本地 release 验证:bun mobile android:<flavor>:release:local走 apps/mobile/scripts/runAndroidLocal.sh,它会处理两层“陈旧代码”陷阱——导出EXPO_LOCAL_NO_BUILD_CACHE=1关闭 apps/mobile/app.config.ts 中的 EAS 构建缓存,并清理 gradlecreateBundle<Variant>JsAndAssets的 UP-TO-DATE 增量产物,确保 APK 内嵌的是最新 JS bundle。交互验证前应确认这是否符合你的验证目标。
  • 权限与模态处理:首次启动或登录等流程常出现系统权限弹窗(如通知、相机、剪贴板),按本文第 8 章策略处理:先describe,暴露不了再screenshot回退,点击Allow类按钮后立即回归describe。

综上,argent-device-interact提供了一套平台无关、坐标归一化、可序列化、可回放的设备交互原语,是本仓库 Agent 在 iOS 模拟器与 Android 模拟器上进行 UI 操作、导航与验证的统一入口。

  • 区块链
  • DeFi
  • 前端
  • 移动开发

【免费下载链接】interface

🦄 Open source interfaces for the Uniswap protocol

项目地址:https://gitcode.com/gh_mirrors/in/interface
点击查看免费下载

相关推荐

上一篇:Node.js后端开发2025年完整学习路线图:从入门到架构师的三阶段实战指南
下一篇:Matter(connectedhomeip)Operational State 簇及其派生簇的 code-driven 实现指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

数据库课程设计实战:通讯录管理系统从E-R图到Java联调全链路拆解

简介&#xff1a;这份《通讯录管理系统数据库课程设计报告》面向高校数据库原理与应用课程的选课学生&#xff0c;帮助完成从需求分析到运行维护的完整课程设计任务。资源包内含1个docx文档&#xff0c;压缩包约840KB&#xff0c;以课程设计报告为主体&#xff0c;涵盖摘要、绪…

作者头像 李华
网站建设 2026/10/12 1:17:36

springboot毕设选题露营地管理系统设计与实现

&#x1f345;选题推荐——以防找不到我们&#xff0c;点击上方订阅专栏✌✌\ Java毕设实战项目 Python毕设项目源代码 asp.net毕业设计项目 Uniapp安卓毕业设计项目 node.js毕业设计项目 python毕业设计 微信小程序毕业设计项目 php毕业设计 &#x1f447;&#x1f3fb;&#…

作者头像 李华
网站建设 2026/10/12 1:17:18

时间轴+流程图PPT模板:逻辑可视化与高效修改指南

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

作者头像 李华
网站建设 2026/10/12 1:17:12

CATIA参考元素本质:点线面是空间坐标锚点而非绘图标记

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

作者头像 李华
网站建设 2026/10/12 1:16:09

天龙八部私服MySQL 5.0.45源码编译实战指南

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

作者头像 李华