Unity 笔记二:数字孪生智慧城市中 LookAt 与 Cursor 的协同配置到 TaoToken
1. 数字孪生智慧城市里相机 LookAt 与 Cursor 到底怎么配合做城市三维可视化项目时相机控制和光标交互往往是两个被分开处理的问题但它们在数字孪生场景里其实是一套联动系统。我先把场景说清楚你有一个智慧城市沙盘里面有楼宇、道路、管网、传感器点位用户需要既能像 RTS 一样自由浏览全局又能点击某栋楼弹出能耗面板还能一键把镜头拉近到某个路口做巡检。这时候相机不能只是简单跟随光标也不能只是显示或隐藏两者必须协同。核心检索词先摆出来Unity 数字孪生智慧城市中的 LookAt 与 Cursor 协同配置指的是用Transform.LookAt控制相机或标注物朝向目标点同时用Cursor.lockState和Cursor.visible管理鼠标状态让“自由浏览”和“精确拾取”两种模式平滑切换。它适合做城市三维可视化、园区数字孪生、交通态势大屏的开发者尤其是已经会用 Unity 基础操作、但一遇到相机翻转或光标乱跳就卡住的人。我试过在一个园区项目里最初把 LookAt 直接挂在相机上结果相机 Z 轴指向目标后整个画面倒过来了。原因在 excerpt 里也提到过LookAt默认让物体的 Z 轴前向轴指向目标而相机的 Z 轴是朝向屏幕外的所以直接 LookAt 会导致朝向与预期相反。解决办法不是不用 LookAt而是让物体朝向与摄像机朝向一致或者对相机使用“看向目标但保持 up 向量”的写法。另一个常见问题是 Cursor 状态和相机模式没有绑定。比如用户按 Esc 解锁鼠标去点 UI但相机还在用鼠标移动量旋转结果鼠标一移动视角就乱转。所以这篇会把 LookAt 的朝向修正、Cursor 的锁定/显示、以及新输入系统下的相机移动旋转串成一条可复制的配置链路最后再落到 TaoToken 的统一 Key/API 通道上做一次调用验证确保你的原型不仅能跑还能接上模型服务做智能问答或标注生成。2. TaoToken 前置统一 Key 与 API 通道准备在进入 Unity 配置之前先把 TaoToken 这一侧准备好。TaoToken 是一个面向开发者的模型调用统一入口你可以把它理解成一个“API 网关 Key 管理台”同一个 Key 可以走不同模型的对话、代码补全、Agent 任务不用在每个项目里散落一堆密钥。对于数字孪生智慧城市这种需要接大模型做语义查询、报告生成、点位描述的场景统一通道能省掉很多切换成本。你需要先拿到三件套Base URL、API Key、Model ID。Base URL 用https://taotoken.net/api注意这个地址不带 UTM 参数直接作为请求根路径。API Key 在控制台创建建议按项目命名比如unity-digital-twin-dev方便后面轮换。Model ID 根据你要做的任务选做城市问答和标注生成可以用通用对话模型做代码辅助可以用 coding 类模型。具体动作打开https://taotoken.net/console进入控制台在 API Keys 页面点创建复制生成的 Key 并保存到本地环境变量不要硬编码进 Unity 脚本。然后打开https://taotoken.net/doc确认当前支持的模型列表和请求格式。如果你后面要做长期编码或 Agent 任务可以看https://taotoken.net/coding-plan了解套餐如果只是想先验证模型对话用https://taotoken.net/api-keys管理 Key 即可。这里给一个最小验证命令用 curl 确认 Key 和通道是通的curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: your-model-id, messages: [ {role: user, content: 用一句话描述数字孪生智慧城市中相机LookAt的作用} ] }如果返回里有choices字段和内容说明通道正常。注意不要把 Key 写进截图或公开仓库Unity 项目里建议用Environment.GetEnvironmentVariable读取或者放在不纳入版本管理的secrets.json里。这一步做完后面 Unity 里的 C# 请求才能复用同一套凭证。3. 可复制配置LookAt 朝向修正与 Cursor 状态机这一节直接给可复制的配置片段。先解决 LookAt 朝向问题。在智慧城市场景里你可能有多个需要朝向相机的对象比如楼宇标签、告警图标、巡检点标记。如果直接transform.LookAt(Camera.main.transform.position)标签的 Z 轴会指向相机但正面可能背对导致文字镜像或倒置。修正方式是让对象的前向与相机前向一致using UnityEngine; public class BillboardToCamera : MonoBehaviour { public Camera mainCamera; void LateUpdate() { if (mainCamera null) return; transform.LookAt(mainCamera.transform.position); transform.forward mainCamera.transform.forward; } }这段放在标签或图标上LateUpdate保证在相机移动之后执行避免抖动。注意transform.forward mainCamera.transform.forward这一行是关键它把对象的 Z 轴重新对齐到相机朝向解决倒向问题。接下来是 Cursor 状态机。数字孪生场景通常有三种模式浏览模式鼠标锁定相机旋转、拾取模式鼠标可见点击选择、UI 模式鼠标可见操作面板。用枚举管理比散落的 bool 更清晰public enum InteractionMode { Browse, Pick, UI } public class CursorModeController : MonoBehaviour { public InteractionMode currentMode InteractionMode.Browse; public void SetMode(InteractionMode mode) { currentMode mode; switch (mode) { case InteractionMode.Browse: Cursor.lockState CursorLockMode.Locked; Cursor.visible false; break; case InteractionMode.Pick: case InteractionMode.UI: Cursor.lockState CursorLockMode.None; Cursor.visible true; break; } } void Update() { if (Input.GetKeyDown(KeyCode.Escape)) { SetMode(InteractionMode.UI); } } }如果你用的是新输入系统把Input.GetKeyDown换成Keyboard.current.escapeKey.wasPressedThisFrame。这里要注意CursorLockMode.Locked会把鼠标锁到屏幕中心适合 FPS 式浏览CursorLockMode.Confined适合 RTS 式限制在窗口内。智慧城市大屏项目里如果用户需要拖拽地图建议用Confined而不是Locked。然后是相机控制器与 Cursor 的联动。下面这个CameraController整合了移动、旋转和模式切换参数用[Header]分组方便在 Inspector 里调using UnityEngine; using UnityEngine.InputSystem; public class CameraController : MonoBehaviour { [Header(移动设置)] public float moveSpeed 10f; [Header(旋转设置)] public float lookSpeed 2f; public float minRotation -85f; public float maxRotation 85f; [Header(模式)] public InteractionMode mode InteractionMode.Browse; private Vector2 moveInput; private Vector2 lookInput; private float yRotate 0f; private float xRotate 0f; void OnEnable() { Cursor.lockState CursorLockMode.Locked; Cursor.visible false; } void OnDisable() { Cursor.lockState CursorLockMode.None; Cursor.visible true; } void Update() { if (Keyboard.current.escapeKey.wasPressedThisFrame) { mode InteractionMode.UI; Cursor.lockState CursorLockMode.None; Cursor.visible true; } if (Mouse.current.leftButton.wasPressedThisFrame mode InteractionMode.UI) { mode InteractionMode.Browse; Cursor.lockState CursorLockMode.Locked; Cursor.visible false; } if (mode InteractionMode.Browse) { Move(); Look(); } } private void Move() { Vector3 forward transform.forward; Vector3 right transform.right; Vector3 moveDirection (forward * moveInput.y right * moveInput.x).normalized; transform.position moveDirection * moveSpeed * Time.deltaTime; } private void Look() { yRotate lookInput.x * lookSpeed; xRotate - lookInput.y * lookSpeed; xRotate Mathf.Clamp(xRotate, minRotation, maxRotation); transform.rotation Quaternion.Euler(xRotate, yRotate, 0f); } }注意minRotation和maxRotation我设成 -85 到 85而不是 -90 到 90这是为了避免万向节死锁。excerpt 里提到 -90 到 90 也可以但实际项目里 85 更稳。另外moveInput和lookInput需要通过 Input Action 事件赋值如果你还没建.inputactions资源可以在OnEnable里用controls.Camera.Move.performed ctx moveInput ctx.ReadValueVector2();这种方式注册。如果你要把这些配置和 TaoToken 的模型调用串起来可以在拾取模式下点击楼宇后把楼宇 ID 发给模型做描述生成。请求体用 JSON路径和字段保持和文档一致{ model: your-model-id, messages: [ {role: system, content: 你是智慧城市数字孪生助手根据楼宇ID生成简短描述。}, {role: user, content: 楼宇ID: B-1024, 类型: 办公楼, 能耗等级: A} ], temperature: 0.3 }这个 JSON 可以直接放进 Unity 的UnityWebRequest里Base URL 用https://taotoken.net/apiHeader 带Authorization: Bearer 你的Key。注意 Model ID 要和你在控制台看到的一致不要写错大小写。4. 验证请求与成功结果从 Unity 到 TaoToken 的完整链路配置写完后必须做一次端到端验证。验证分两层第一层是 Unity 内部相机和光标行为是否正确第二层是 TaoToken 请求是否返回预期结果。先验证相机和光标。在场景里放一个 Cube 作为楼宇挂上BillboardToCamera把 Main Camera 拖进去。运行后按 WASD 移动鼠标旋转视角观察 Cube 上的标签是否始终正面朝向相机且没有倒置。然后按 Esc鼠标应该解锁并显示相机停止旋转再点鼠标左键鼠标重新锁定并隐藏相机恢复旋转。如果标签在相机旋转时抖动检查是不是用了Update而不是LateUpdate如果鼠标解锁后相机还在转检查mode判断是否生效。再验证 TaoToken 请求。在 Unity 里写一个简单的TaoTokenClientusing UnityEngine; using UnityEngine.Networking; using System.Collections; using System.Text; public class TaoTokenClient : MonoBehaviour { private string apiKey; private string baseUrl https://taotoken.net/api; private string modelId your-model-id; void Start() { apiKey System.Environment.GetEnvironmentVariable(TAOTOKEN_API_KEY); StartCoroutine(SendRequest(用一句话描述数字孪生智慧城市中相机LookAt的作用)); } IEnumerator SendRequest(string prompt) { string json {\model\:\ modelId \,\messages\:[{\role\:\user\,\content\:\ prompt \}]}; byte[] body Encoding.UTF8.GetBytes(json); UnityWebRequest request new UnityWebRequest(baseUrl /v1/chat/completions, POST); request.uploadHandler new UploadHandlerRaw(body); request.downloadHandler new DownloadHandlerBuffer(); request.SetRequestHeader(Content-Type, application/json); request.SetRequestHeader(Authorization, Bearer apiKey); yield return request.SendWebRequest(); if (request.result UnityWebRequest.Result.Success) { Debug.Log(TaoToken 返回: request.downloadHandler.text); } else { Debug.LogError(请求失败: request.error 响应: request.downloadHandler.text); } } }运行后看 Console。成功时你会看到类似{choices:[{message:{content:...}}]}的返回说明 Key、Base URL、Model ID 三件套都对。如果返回 401检查 Key 是否复制完整、有没有多余空格如果返回local proxy failed检查网络是否能直连taotoken.net如果返回里没有choices检查 Model ID 是否在文档列表里。验证通过后你可以把拾取到的楼宇信息拼进 prompt让模型生成描述并显示在 UI 面板上。这样数字孪生场景就不只是静态展示而是能根据用户点击动态生成语义信息。如果你要做更复杂的 Agent 任务比如自动巡检报告可以走https://taotoken.net/coding-plan了解长期方案如果只是验证模型对话用https://taotoken.net/api-keys管理 Key 就够了。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节按真实报错来排。第一个高频错误是 401 Unauthorized。在 Unity 里通常表现为request.error返回HTTP/1.1 401 Unauthorized响应体里可能有invalid api key。原因一般是 Key 没读到、Key 过期、或者 Header 拼写错误。检查Authorization是不是Bearer加空格再加 Key检查环境变量是否在 Unity 启动前设置好。如果你在 Editor 里改了环境变量需要重启 Unity 才能读到。第二个是local proxy failed。这个报错通常出现在请求根本没到达 TaoToken 服务端而是被本地网络层拦住了。检查你的 Base URL 是不是写成了https://taotoken.net/api不要多加斜杠或路径。检查系统代理设置是否干扰了 Unity 的UnityWebRequest。如果你在公司网络里确认防火墙允许对taotoken.net的 HTTPS 出站。这个错误和 Key 无关先排网络再排凭证。第三个是reading choices相关错误比如Cannot read property choices of undefined或 C# 里反序列化后choices为 null。这通常说明返回的 JSON 结构和你预期的不一样。可能原因Model ID 写错导致服务端返回错误对象而不是正常响应请求体里messages格式不对比如 role 写成了user以外的值或者temperature传了字符串而不是数字。建议先把request.downloadHandler.text完整打印出来看服务端到底返回了什么。第四个是 OAuth 相关报错。如果你在配置 Claude Code 或类似工具时看到 OAuth 失败注意 TaoToken 的 API 通道用的是 Bearer Key不是 OAuth 流程。如果你在settings.json或auth.json里配置确保字段是apiKey或api_key而不是oauthToken。对于 Claude Code 类工具Base URL 填https://taotoken.net/apiKey 填控制台生成的 KeyModel ID 填文档里的模型名。三件套缺一不可只填 Base URL 不填 Key 会直接 401。还有一个容易忽略的问题Cursor 锁定后 UI 按钮点不到。这是因为CursorLockMode.Locked把鼠标锁在屏幕中心UI 射线检测不到。解决办法是在打开 UI 面板前调用SetMode(InteractionMode.UI)把lockState设为None并visible true。关闭面板后再切回Browse。如果你用CursorLockMode.Confined鼠标可以在窗口内移动但不会移出窗口适合需要拖拽但又不想完全锁定的场景。最后检查 LookAt 的坐标系。Unity 是左手坐标系Z 轴向前Y 轴向上。LookAt会让 Z 轴指向目标但如果你对象的模型本身朝向是反的就需要额外旋转 180 度。可以在BillboardToCamera里加一个offsetRotation参数在LateUpdate最后乘上去transform.rotation * Quaternion.Euler(0, 180f, 0);这样即使模型导入时朝向不对也能通过配置修正不用改模型文件。6. 继续接入用 TaoToken 做智慧城市语义交互相机和光标配好之后下一步是让场景“会说话”。数字孪生智慧城市的价值不只是看而是能问。比如用户点击一栋楼场景把楼宇 ID、类型、能耗等级发给 TaoToken模型返回一段描述或建议显示在侧边面板。这个链路复用你前面验证过的TaoTokenClient只需要把 prompt 换成动态拼接的楼宇信息。如果你要做代码辅助比如自动生成相机控制脚本或输入配置可以用https://taotoken.net/coding-plan了解长期编码方案。如果只是偶尔调用模型对话做验证用https://taotoken.net/api-keys管理 Key配合https://taotoken.net/doc查请求格式就够了。Claude Code 类工具接入时Base URL 用https://taotoken.net/apiKey 用控制台生成的Model ID 用文档里的三件套写全再测。实际项目里我建议把 Cursor 模式切换和相机控制做成一个InteractionManager统一管理 Browse、Pick、UI 三种状态避免多个脚本各自改Cursor.lockState导致状态冲突。同时把 TaoToken 请求封装成异步方法加超时和重试避免网络波动卡住主线程。这样你的智慧城市原型就能从“能看”走到“能问、能答、能交互”。

相关新闻

Zion 接入 Gemini 3.5 flash 后,AI Agent Builder 的 BYOM 配置怎么改到 TaoToken

Zion 接入 Gemini 3.5 flash 后,AI Agent Builder 的 BYOM 配置怎么改到 TaoToken

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

2026/10/11 7:05:37 阅读更多 →
2026告别漫长等待:百度网盘冷门资源类似pandownload加速法

2026告别漫长等待:百度网盘冷门资源类似pandownload加速法

很多人在日常保存或者获取资料的时候,经常会遇到文件传输进度停滞不前的情况。面对几十兆甚至几个小容量的文件,进度条却像蜗牛爬行一样缓慢,确实很容易让人感到焦躁和无奈。 其实在很多时候,下载速度提不上来不一定是因为外界的…

2026/10/11 7:05:36 阅读更多 →
OWASP 五大 AI 安全框架:从对话、Agent、技能到协议的全链路防护体系

OWASP 五大 AI 安全框架:从对话、Agent、技能到协议的全链路防护体系

随着生成式AI、自主智能体(Agent)、插件技能生态的大规模落地,AI安全风险早已不再局限于“模型幻觉、提示注入”等基础问题。从模型对话输出、智能体自主决策,到第三方技能插件执行、内外系统协议交互,每一层链路都存在…

2026/10/11 7:05:36 阅读更多 →

最新新闻

【单片机毕业设计】基于单片机的自行车骑行定位与运动数据监测装置设计 基于物联网的骑行速度里程与定位追踪监测系统设计(030205)

【单片机毕业设计】基于单片机的自行车骑行定位与运动数据监测装置设计 基于物联网的骑行速度里程与定位追踪监测系统设计(030205)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/10/11 7:53:04 阅读更多 →
厦门Java后端面试复盘:分布式事务、库存扣减与订单状态机

厦门Java后端面试复盘:分布式事务、库存扣减与订单状态机

上周刚从厦门回来,一口气面了两家公司的Java后端岗位。趁记忆还热乎,把这次的面试总结整理出来。如果你也在看厦门的后端机会,或者正准备约面试,这篇复盘应该能给你一些参考。两家公司一家是跨境ERP自研,另一家做本地生…

2026/10/11 7:53:04 阅读更多 →
Flask实现企业员工人事工资管理系统前台:从登录到工资查询的完整实践

Flask实现企业员工人事工资管理系统前台:从登录到工资查询的完整实践

前阵子帮一家做内部管理系统的小公司搭了一个员工自助门户,跑起来之后身边好几个同事都问我说,你这套“前台”到底是怎么拆出来的,跟后台管理端混在一起会不会乱。借着这个机会,我把PythonFlask实现企业员工人事工资管理系统前台的…

2026/10/11 7:53:04 阅读更多 →
WOFOST与AquaCrop作物模型对比:机理、参数与应用选择

WOFOST与AquaCrop作物模型对比:机理、参数与应用选择

做作物模型的人,迟早会在某个项目里同时撞见WOFOST和AquaCrop这两个名字。一个来自欧洲,一个出自联合国粮农组织,都是全球应用最广的作物生长模型,但如果你只把它们当作“模拟产量的工具”来用,那从一开始就搞错了方向…

2026/10/11 7:53:04 阅读更多 →
VLX-Seek实时视觉理解模型:架构设计与工程优化实战

VLX-Seek实时视觉理解模型:架构设计与工程优化实战

1. 从标题拆解 VLX-Seek 的真实定位1.1 这个标题到底在说什么第一次看到“VLX-Seek 实时视觉理解模型”这个标题,我脑子里跳出来的第一个判断是:这不是一个单纯的图像分类模型,也不是一个只做目标检测的模型,而是一个把“看”和“…

2026/10/11 7:53:04 阅读更多 →
告别语义漂移:用 BM25 与向量检索打造个人日记的混合召回(Hybrid Search)

告别语义漂移:用 BM25 与向量检索打造个人日记的混合召回(Hybrid Search)

秋雨淅淅沥沥下了一整天,空气里泛着潮湿的泥土香气。我坐在书房里,试图从这几年积攒的上千篇日记与手账随笔中,找出一年前在某家咖啡馆尝过的“桂花乌龙生椰拿铁”。 我在私有 RAG 助手里键入了这几个字,屏幕很快吐出了一堆相关记…

2026/10/11 7:52:03 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 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/10 5:23:50 阅读更多 →
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/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练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/10 10:38:42 阅读更多 →