Flutter在OpenHarmony上实现房间列表:从环境搭建到状态管理实战
房间列表这个功能是我在做家具购买记录 App 时第一个从单一页面迈向多房间数据管理的转折点。OpenHarmony 设备上跑 Flutter听着像是个折腾活儿但实际走通之后你会发现这套组合比想象中顺手。这篇文章不聊概念直接把我实现房间列表的完整过程拆开给你看——从环境准备到 Provider 状态管理再到 UI 布局和真机调试每一步都附上我踩过的坑和当时的思考。1. 为什么我用 Flutter 来写 OpenHarmony 应用先说结论如果你只想为鸿蒙生态写一个应用ArkTS 确实是最正统的选择。但如果你的目标是一套代码多个平台都能跑或者你本身已经熟悉 Flutter 而不想再学一套 UI 框架那 Flutter for OpenHarmony 是一条值得走的路。1.1 Flutter 与 ArkTS 的选型取舍我在决定技术方案时列过一张对比表维度FlutterArkTS跨平台能力同一套代码可编译到 Android、iOS、Web、OpenHarmony仅 OpenHarmony及鸿蒙系UI 渲染自绘引擎跨端表现一致基于鸿蒙原生组件系统风格强开发语言DartTypeScript 超集ArkTS组件生态沿用 pub.dev 大量 Flutter 包多数可直接用主要靠鸿蒙官方和贡献者维护的库状态管理Provider、Riverpod、Bloc 等丰富方案ArkData、ViewModel 等原生方案学习成本会 Flutter 几乎零额外成本需要学习 ArkTS 语法和鸿蒙 API对我这个场景来说核心需求是快速迭代、界面统一、数据管理清晰而且我手头已经有 Flutter 的开发经验于是选择了 Flutter。唯一需要留意的就是你最终要构建ohostarget这跟常规的apk或app构建流程不同后面会细说。1.2 Flutter for OpenHarmony 目前在实战中的成熟度这个适配项目从官方flutter/flutter的ohos分支拉出来社区一直在推进。我在实操过程中最有感触的一点是纯 UI 层面和 Dart 逻辑层面可以完全复用真正需要额外处理的是系统能力和原生插件。比如拍照、文件读写这种涉及原生能力的功能需要确认 Flutter 插件是否已经有 OpenHarmony 的适配实现或者是否要用通道自己写。但这篇文章要做的房间列表相对简单不涉及原生调用核心就是干净的数据管理和 UI 表现所以 Flutter 的适配问题基本不会碰到。2. 开发环境搭建与工程初始化这一步最容易劝退如果你不是第一次接触 Flutter环境搭建会很快但如果你在 Windows 上同时想处理 OpenHarmony target那有几个点需要特别小心。2.1 安装 Flutter SDK 的 ohos 分支这里必须强调一个容易踩的坑不要直接下载普通 Flutter SDK要使用适配了 OpenHarmony 的分支。常规 Flutter 的stable分支已经支持过了 OpenHarmony 的插桩构建但为了保险我使用的是社区维护的flutter_flutter项目。我的实际操作是这样的git clone -b dev https://gitee.com/openharmony-sig/flutter_flutter.git git clone -b dev https://gitee.com/openharmony-sig/flutter_engine.git git clone -b master https://gitee.com/openharmony-sig/flutter_packages.git这三个仓库分别对应 Flutter 框架、引擎和插件仓库。克隆完成后还需要准备 OpenHarmony 的 SDK我使用的是通过 DevEco Studio 下载的ets和toolchains目录。在配置完环境变量后可以用以下命令验证flutter doctor如果你在flutter doctor的输出里看到 OpenHarmony 的检测项说明环境基本就位。这里有一个我踩过的坑如果直接用官方渠道下载 Flutter SDK执行flutter create --platformsohos会失败因为它没有内置 ohos 的 platform 支持。2.2 创建工程时不能漏掉的参数工程创建这一步公式很简单flutter create --platformsohos,android .我加了android是为了方便在 Android 模拟器上快速调试 UI 表现毕竟 OpenHarmony 模拟器不是到处都有。如果你不需要 Android target可以只保留ohos。创建完之后检查pubspec.yaml默认依赖是cupertino_icons然后我追加了provider用于状态管理。dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.6 provider: ^6.1.22.3 DevEco Studio 与项目目录结构的关系在 Flutter 工程生成后你会看到一个ohos目录这就是 OpenHarmony 的壳工程。你在 Flutter 层写的 Dart 代码会被编进这个壳里最终打成.hap包。用 DevEco Studio 打开ohos目录时它会让你配置 SDK 路径同时可能触发 Gradle 和 Cmake 的下载这一步挺耗时。第一次打开时最好保持网络畅通耐心等进度条走完。如果中途失败直接在 DevEco 里执行菜单栏的File - Sync and Refresh Project重试即可。3. 房间数据模型与 Provider 状态管理设计一个房间列表看似只是把几个房间名字展示出来但实际上要考虑的数据问题不少每个房间有哪些家具、家具花了多少钱、购买时间是什么时候、房间的封面图用什么占位。数据模型理清楚后面的界面和交互才不会乱。3.1 先定义 FurnitureItem 还是先定义 Room我习惯从最细粒度的实体开始反推。这个 App 的核心实体是家具家具归属于房间所以先定义FurnitureItem再定义Room会更自然。class FurnitureItem { final String id; final String name; final String roomId; final double price; final String purchaseDate; final String imagePath; // 本地路径或网络 URL FurnitureItem({ required this.id, required this.name, required this.roomId, required this.price, required this.purchaseDate, this.imagePath , }); }房间模型里除了房间名和 ID还需要一个图标标识。考虑到客厅卧室书房这类固定分类我直接用roomType枚举配合预设图标避免让用户自己传图标文件。enum RoomType { livingRoom, bedroom, kitchen, study, bathroom, other } class Room { final String id; final String name; final RoomType type; final ListFurnitureItem furnitureList; Room({ required this.id, required this.name, required this.type, this.furnitureList const [], }); }3.2 Provider 的角色与为什么不用 setState房间列表页面有一个典型场景用户在房间 A 里新增了一件家具返回列表时房间 A 的总价和家具数量要同步变化。如果只用setState管理这种跨页面数据同步会变得很痛苦。于是我用ChangeNotifier Provider。这个方案不重不需要引入 Bloc 那种复杂的事件流学习成本低当前项目规模下完全够用。class RoomStore extends ChangeNotifier { ListRoom _rooms []; ListRoom get rooms List.unmodifiable(_rooms); void addRoom(Room room) { _rooms.add(room); notifyListeners(); } void addFurnitureToRoom(String roomId, FurnitureItem item) { final index _rooms.indexWhere((r) r.id roomId); if (index ! -1) { _rooms[index].furnitureList.add(item); notifyListeners(); } } void deleteFurniture(String roomId, String furnitureId) { ... } }在main.dart里注入 Storevoid main() { runApp( ChangeNotifierProvider( create: (_) RoomStore()..loadMockData(), child: const FurnitureApp(), ), ); }组件内部读取数据就非常清爽了final roomStore context.watchRoomStore();这里就回答了热门搜索里的 flutter provider 怎么用——它的核心用法就是定义 ChangeNotifier、在顶层传入、在需要的 Widget 里watch或read。3.3 模拟数据的组织方式在还没有接数据库之前我直接在 Store 里构造了一批初始数据用来验证 UI 效果。这里有一个值得分享的小技巧把模拟数据的构建独立成一个方法并在类型注解中统一使用ListRoom以后替换成本地数据库或后端接口时只需改动 Store 内部实现View 层不用动。void loadMockData() { _rooms [ Room( id: room_1, name: 客厅, type: RoomType.livingRoom, furnitureList: [ FurnitureItem( id: f_1, name: 双人布艺沙发, roomId: room_1, price: 3199, purchaseDate: 2025-03-12, ), FurnitureItem( id: f_2, name: 实木茶几, roomId: room_1, price: 1299, purchaseDate: 2025-03-12, ), ], ), Room(id: room_2, name: 主卧, type: RoomType.bedroom, furnitureList: [...]), ]; notifyListeners(); }4. 房间列表 UI 实现从卡片布局到空状态处理UI 这部分我走了三版第一版用ListView堆卡片比较保守第二版改成了GridView双列房间数量少时显得空旷最终折中方案是不固定双列而是让卡片自适应宽度并保留底部的添加房间入口。4.1 页面整体结构房间列表页主要由三块组成顶部的统计概览、中部的房间网格、右下角的悬浮添加按钮。统计概览和房间数据都来自 Provider这样就不会出现页面 A 加了房间、页面 B 总数没更新的问题。Scaffold( body: SafeArea( child: ConsumerRoomStore( builder: (context, store, child) { if (store.rooms.isEmpty) { return const EmptyRoomView(); } return CustomScrollView( slivers: [ SliverToBoxAdapter(child: SummaryHeader(rooms: store.rooms)), SliverPadding( padding: const EdgeInsets.all(16), sliver: SliverGrid( gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 220, mainAxisSpacing: 12, crossAxisSpacing: 12, childAspectRatio: 0.82, ), delegate: SliverChildBuilderDelegate( (context, index) RoomCard(room: store.rooms[index]), childCount: store.rooms.length, ), ), ), ], ); }, ), ), floatingActionButton: FloatingActionButton( onPressed: _showAddRoomDialog, child: const Icon(Icons.add), ), )注意我用的是Consumer而不是context.watch纯粹是因为 builder 里同时要使用 store 数据并处理空状态逻辑这样包裹范围更明确。4.2 房间卡片的信息层级与视觉表现每张房间卡片里我放了四类信息房间名称与类型、家具数量、总花费、封面图没有真实图片时用图标。信息层级要清楚不能平均分配。class RoomCard extends StatelessWidget { final Room room; const RoomCard({super.key, required this.room}); override Widget build(BuildContext context) { final totalPrice room.furnitureList.folddouble( 0, (sum, item) sum item.price); return Card( clipBehavior: Clip.antiAlias, elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: InkWell( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) FurnitureListPage(roomId: room.id), ), ); }, child: Padding( padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(12), ), child: Icon(_iconForRoomType(room.type)), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(room.name, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600)), const SizedBox(height: 4), Text(${room.furnitureList.length} 件家具 · ¥${totalPrice.toStringAsFixed(0)}, style: TextStyle( fontSize: 12, color: Colors.grey[600])), ], ), ), ], ), ], ), ), ), ); } }这里有个容易忽略的点点击卡片跳转到家具列表页面时一定要传roomId而不是传整个Room对象。因为家具列表页里可能会修改房间内的家具数据如果直接传对象引用会让数据流变得不可追踪传 ID 后家具列表页统一通过 Provider 获取最新房间数据能有效避免旧数据覆盖新数据的问题。4.3 自定义加载占位与空状态联网加载或首次进入没有数据时我设计了一个简易的骨架屏让界面不会一下子空白。骨架屏的做法很直接用灰底圆角块模拟房间卡片的尺寸再配合一个轻微透明度动画。class RoomCardSkeleton extends StatelessWidget { const RoomCardSkeleton({super.key}); override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.03), borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ _SkeletonBox(width: 40, height: 40, borderRadius: 12), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const _SkeletonBox(width: 80, height: 16), const SizedBox(height: 8), const _SkeletonBox(width: 120, height: 12), ], ), ), ], ), ], ), ); } }空状态页面也不复杂居中放一个暂无房间的图标和文字外加一个去添加房间按钮。这样的交互闭环虽然简单但实际体验会比白屏好很多。4.4 添加房间弹窗的实现细节默认条目里用的是中文类型所以新增房间时我用了底部弹窗加表单的方式而不是生硬的全屏页面。弹窗里包含房间名称输入框和类型选择器确认后调用store.addRoom()。一个细节表单校验要阻止房间名为空的情况用TextFormField的validator能顺手解决。同时如果用户输入重名房间我也是允许的——因为现实中可能有两个储物间。如果要做额外限制可以在addRoom方法里判断同名但这不是当前需求的重点。5. 运行到 OpenHarmony 设备/模拟器的流程与踩坑记录在写房间列表的过程中我把应用跑到了 OpenHarmony 模拟器上也插过真机。这个环节比普通 Flutter 开发要多几步但也完全在可控范围内。5.1 构建 ohos target 的正确姿势首先确认你当前设备已连接可以用hdc list targets查看。hdc 是 OpenHarmony 的命令行工具类似于 adb。接下来运行flutter build hap --debug如果你没有在--platforms里加ohos这一步会报错说找不到 ohos platform。如果正常构建你会在build/ohos目录下生成.hap文件。然后使用 hdc 安装hdc install build/ohos/app/build/outputs/default/xxx.hap这里有个常见问题hdc 安装 .hap 时提示签名不对。OpenHarmony 默认情况下只允许安装带签名的 hap。如果调试阶段遇到这个问题一种简单做法是在 DevEco Studio 里配置自动签名或者生成调试证书导入。我在做 UI 层调试时直接用 DevEco 的自动签名功能解决的没有去折腾手动签名。5.2 真机调试时的日志查看方法运行后想看print日志用hdc shell hilog即可。过滤 Flutter 的关键字的命令是hdc shell hilog | grep flutter由于 Flutter 引擎在 ohos 上会把 Dart 侧的输出转发到 hilog所以这个方式能覆盖绝大多数调试场景。相比之下Flutter 默认的flutter logs在当前 OpenHarmony 适配下并不总是可用优先用 hilog。对了还有一个很实用的小技巧你可以在工程里通过debugPrint打印带 tag 的内容然后 grep tag 的名称例如debugPrint([RoomList] refresh complete, total${store.rooms.length});然后hdc shell hilog | grep RoomList这样只看关心的日志不会被引擎日志淹没。5.3 与 Android 模拟器的差异点OpenHarmony 模拟器的某些渲染表现和 Android 有细微差别。最明显的是中文字体的字重渲染OpenHarmony 默认字体在某些像素密度下偏细如果你的卡片文字用了FontWeight.w600看起来可能不如 Android 上醒目。但这不影响布局和数据逻辑发布到真机时按需微调 fontFeature 或字体 fallback 即可。另外热重载hot reload在 ohos target 上可用但比 Android 稍微慢一点。我记得有一次修改了 Provider 的notifyListeners()调用时机热重载后 UI 刷新正常这得益于 Flutter 引擎的热重载机制在 OHOS 上已经跑通了。实测下来很稳但还是建议不要频繁热重载改模型结构容易遇到 Dart 侧 AOT/JIT 切换导致的编译缓慢。6. 房间列表后续的可扩展方向房间列表只是第一步。以我目前实现的数据模型后续可以很顺畅地扩展这几个功能按房间查看家具明细房间卡片点击进入家具列表页数据源从Room.furnitureList取即可。家具购买记录筛选按日期范围、按价格区间筛选可以在RoomStore上增加filteredRooms()方法不影响现有页面结构。房间排序与置顶在Room实体上加一个sortWeight字段然后在_rooms排序时处理。持久化存储现在loadMockData()是固定数据后续可以换成sqflite在 OpenHarmony 上可能需要找适配的数据库插件或者直接写 JSON 文件存到应用沙盒目录。我在写这个项目时最大的体会是Flutter for OpenHarmony 的应用开发已经不再是能跑 Demo的程度只要不碰深度系统能力纯 Flutter 的业务页面完全可以平滑迁移到 OpenHarmony。房间列表这种典型的 CRUD 状态管理场景恰好是验证这套技术栈融合是否顺手的最佳试金石。如果你也想在 OpenHarmony 上尝试 Flutter建议从类似名单管理记账列表这种小功能起步先打通环境、再补状态管理最后加交互细节。一条路径走顺了后面再加花瓣组件、动画都是锦上添花而已。

相关新闻

SpringBoot+Vue商铺管理系统源码实战:数据建模到部署全解析

SpringBoot+Vue商铺管理系统源码实战:数据建模到部署全解析

前阵子帮人看了一套企业级商铺管理系统源码,场景挂的是太原学院,技术栈是 SpringBoot Vue MyBatis MySQL,文件命名里写着“完整版”。我把 SQL 脚本导进去、后端跑起来、前端调通之后,第一感觉是这项目比市面上大多数“毕设源码…

2026/10/11 13:13:46 阅读更多 →
基于SpringBoot2与Vue3的多维分类知识管理系统实战解析

基于SpringBoot2与Vue3的多维分类知识管理系统实战解析

做毕业设计、课设或者企业内部的小型知识管理模块,这几年我越来越频繁地被问到同一个技术组合:SpringBoot2 Vue3 MyBatis-Plus MySQL8.0。这套东西不是哪个商业框架推出来的噱头,而是 Java Web 全栈开发里最“能打”的一套组合拳。最近正好…

2026/10/11 13:14:22 阅读更多 →
SpringBoot医院线上诊疗系统毕设:从数据库设计到接口安全完整指南

SpringBoot医院线上诊疗系统毕设:从数据库设计到接口安全完整指南

毕业设计这个选题,我这两年见了不下几十次——医院线上诊疗管理系统。说实话,它之所以成为Java方向的热门毕设,不是因为难度高,而是因为业务链条足够完整:用户、医生、科室、预约、病历、诊疗、药品,每个环…

2026/10/10 9:59:33 阅读更多 →

最新新闻

Django+Vue外卖点餐系统毕设指南:从建表到联调全流程

Django+Vue外卖点餐系统毕设指南:从建表到联调全流程

简介:一套基于Python Django与Vue.js开发的外卖点餐系统毕业设计项目,采用B/S架构,适合计算机相关专业学生作为毕业设计或课程设计参考。前端覆盖首页、菜品详情、订单中心、用户中心等核心用户场景;后台提供总览、订单管理、菜品…

2026/10/11 13:14:52 阅读更多 →
如何在 Virtual Mac 上 5 分钟装好 macOS:新手保姆级快速上手教程

如何在 Virtual Mac 上 5 分钟装好 macOS:新手保姆级快速上手教程

【免费下载链接】VirtualMacOniPad People have dreamed of running macOS on iPad for more than a decade. Today, that dream comes true. With Virtual Mac, iPad finally breaks free from iPadOS, enabling pro apps like Xcode, Terminal, Final Cut Pro, Logic Pro, an…

2026/10/11 13:14:52 阅读更多 →
Kubernetes弹性伸缩实战:HPA、VPA与Cluster Autoscaler原理与配置

Kubernetes弹性伸缩实战:HPA、VPA与Cluster Autoscaler原理与配置

这两年只要跟Kubernetes沾边的团队,几乎都会聊到弹性伸缩。我这些年在一线折腾过不少集群,从最早以为加个 HPA 就万事大吉,到后来被线上抖动、扩容滞后和成本账单来回折磨,才算是把这一整套机制吃透。Kubernetes弹性伸缩实际上不是…

2026/10/11 13:14:52 阅读更多 →
Kubernetes弹性伸缩实战:HPA、VPA、CA与KEDA解析

Kubernetes弹性伸缩实战:HPA、VPA、CA与KEDA解析

做 Kubernetes 这行绕不开的话题就是弹性伸缩。很多人觉得只要部署到集群里,流量大了自然就能扩容,结果一到促销或者突发流量就被报警轰醒,才发现 Pod 数量没有动,节点也快被打满了。原因很简单,Kubernetes 的弹性伸缩…

2026/10/11 13:14:52 阅读更多 →
把CIContext存进@State?SwiftUI-Agent-Skill的“状态即缓存“高级技巧解析

把CIContext存进@State?SwiftUI-Agent-Skill的“状态即缓存“高级技巧解析

【免费下载链接】SwiftUI-Agent-Skill SwiftUI agent skill for Claude Code, Codex, and other AI tools. 项目地址: https://gitcode.com/GitHub_Trending/swi/SwiftUI-Agent-Skill 点击查看 免费下载 SwiftUI-Agent-Skill(技能名 SwiftUI Pro&#x…

2026/10/11 13:14:52 阅读更多 →
健身动作错误归因数据集:专注关节抖动、遮挡漂移与小目标定位

健身动作错误归因数据集:专注关节抖动、遮挡漂移与小目标定位

简介:本资源是面向计算机视觉开发者与运动健康AI研究者的健身动作关键点检测专用数据集,聚焦于自下而上类动作识别与姿态评估,解决健身动作自动判别、姿势纠错与虚拟教练系统构建等核心问题。数据集共1758张真实场景图像(含训练/验…

2026/10/11 13:13:51 阅读更多 →

日新闻

流感时间序列预测实战: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/11 10:45:37 阅读更多 →
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 阅读更多 →