新闻详情

新闻详情

首页 / 资讯中心 / 详情

Flutter适配OpenHarmony实战:喝水提醒App从0到1完整实现

发布时间:2026/9/29 15:37:23来源:尧图网络
Flutter适配OpenHarmony实战:喝水提醒App从0到1完整实现
最近在做一个小项目把 Flutter 应用跑到了 OpenHarmony 系统上做了一个带喝水提醒功能的生活助手 App。折腾过程中踩了不少坑也把一套从环境搭建、功能设计、原生桥接到问题排查的完整链路捋清楚了。这篇文章把整个实现过程整理出来给同样想在 OpenHarmony 上用 Flutter 做实际项目的开发者一个可参考的路径。这套东西适合两类人看一是已经会 Flutter、想尝试鸿蒙生态但不知道怎么入手的开发者二是打算做工具类、助手类应用的团队想快速验证“一套 Flutter 代码能否在 OpenHarmony 设备上跑核心功能”。喝水提醒看着简单但真要拆开来看涉及提醒调度、状态管理、数据持久化、原生通道通信、前后台切换等一整套基础能力做一遍能把 Flutter 在 OpenHarmony 上的开发套路摸个七七八八。1. 项目整体拆解喝水提醒App的需求与架构1.1 一个喝水提醒App到底在解决什么很多人觉得喝水提醒不就是“定个闹钟”吗但实际用下来会发现简单需求里藏着不少细节。真正的问题不是“我要喝水”而是“我忘了喝水”“我不知道自己今天喝了多少”“我工作一忙就两三个小时想不起来起身”。所以这个功能真正要解决的事情有三块规律提醒、记录反馈、历史统计。拿我自己的场景来说项目开发期坐在电脑前经常一坐就是半天等反应过来已经口干舌燥。后来用了一个简单的提醒策略工作时段内每隔一定时间提醒一次每次提醒后记录一杯水当天可以看到自己离目标还差多少。这种“提醒 记录 反馈”的小闭环比单纯闹钟有效得多。功能清单拆出来大概是这些设置每日目标杯数比如8杯、10杯以及提醒的起止时间段在有效时间段内按固定间隔比如60、90、120分钟触发提醒支持“本次跳过”“稍后提醒”“记录喝水”三种操作记录每次喝水时间支持当天进度统计和历史记录查询本地持久化App重启不丢数据这些功能放在 Flutter 里实现多数逻辑完全可以在 Dart 层完成只有“真正在正确时间触发通知”这件事需要借助系统能力。这也是整个项目里 Flutter 和 OpenHarmony 原生层打交道最核心的地方。1.2 为什么用Flutter来写OpenHarmony应用在 OpenHarmony 上开发应用主流选择肯定是 ArkTS 和 ArkUI这个生态是系统原生支持的。但为什么我选了 Flutter说白了就一个原因跨端复用。我手上本来就有一套 Flutter 写的生活助手类应用代码里面已经实现了运动记录、饮水提醒、体重趋势这些模块。如果 OpenHarmony 上要用 ArkTS 重写一遍工作量大且后续多端维护要写两套逻辑。而 Flutter 在 OpenHarmony 上已经有社区维护的适配分支——有专门面向 OpenHarmony 的 Flutter SDK可以让同一套 Dart 代码在 OpenHarmony 设备上编译运行。这个方案的吸引力在于UI 层、业务逻辑层、状态管理层全部复用只替换掉和系统底层相关的桥接层。当然代价也很现实适配分支的版本跟进不如官方 Flutter 快部分插件不一定有 OpenHarmony 版本遇到问题能参考的资料远不如 Android/iOS 多。所以这个方案适合“已经有 Flutter 资产、想在鸿蒙设备上快速落地核心体验”的团队不适合从零开始、目标平台只有 OpenHarmony 的项目——那种情况老老实实用 ArkTS 反而更稳。1.3 整体架构与数据流设计这个项目的架构我觉得可以分四层来看后续所有实现都围绕这个分层展开UI 层纯 Flutter Widget负责设置页、今日进度页、提醒弹窗的展示状态层用 Cubit 管理提醒配置、喝水记录等全局状态桥接层MethodChannel 调用原生通知能力EventChannel 接收原生侧的回传事件原生层OpenHarmony 侧实现通知渠道注册、提醒发送、后台调度等能力数据层本地文件存储保存配置和每日记录数据流上用户设置配置后状态层更新内存数据并写入本地存储同时把下一次提醒时间计算好。提醒时间到了之后有两种路径App 在前台时Dart 层直接弹提醒App 在后台或需要系统级通知时由原生层发送系统通知同时通过 EventChannel 把“提醒已触发”的事件推回给 Dart 层用于刷新页面状态和落记录。2. 环境搭建与工程初始化Flutter适配OpenHarmony实录2.1 SDK与工具链准备要把 Flutter 跑在 OpenHarmony 上第一步就得换一套带 OpenHarmony 平台支持的 Flutter SDK。我用的不是 flutter.dev 官方下载的标准版而是社区维护的 OpenHarmony 分支 SDK从代码仓库拉下来之后本地编译或者直接下载编译好的对应版本。这里有个很关键的认知要提前说清楚OpenHarmony 版的 Flutter SDK 结构里会多出一个 ohos 平台目录flutter 命令行工具也会支持生成 OpenHarmony 工程。环境准备大致是这几步拉取 OpenHarmony 分支的 Flutter SDK配置到环境变量 PATH 里务必确认flutter --version指向的是这套 SDK安装 DevEco Studio用于打开和编译 OpenHarmony 壳工程配置 OpenHarmony SDK路径在 DevEco Studio 里的 SDK Manager 中下载准备一台 OpenHarmony 真机或者用模拟器用于部署调试我在这个环节第一次碰到的问题基本都是“版本不匹配”。OpenHarmony 分支的 Flutter SDK 版本和 DevEco Studio 所带的 OpenHarmony SDK 版本以及设备系统版本三者之间必须对应上。官方仓库的说明文档里通常会写清楚每个版本对应的 OpenHarmony API 版本号我实测下来最好直接按文档推荐组合来盲目用最新版本反而容易翻车。2.2 创建并转换Flutter工程环境就绪之后创建工程比预想中简单。用 OpenHarmony 版 Flutter SDK 执行标准的flutter create命令创建一个项目然后通过命令行或工具生成 ohos 平台工程。这一步完成之后项目目录里会出现一个 ohos 目录里面是 OpenHarmony 壳工程的骨架。我用的是带 OpenHarmony 支持的 Flutter SDK创建命令大概是这样flutter create --project-name water_helper --org com.example water_helper创建完普通工程后再执行生成 ohos 平台目录的命令或者直接检查flutter config是否已启用 ohos 支持。生成成功后目录结构大致会这样water_helper/ ├── lib/ # Dart 业务代码 ├── android/ # Android 壳工程 ├── ios/ # iOS 壳工程 ├── ohos/ # OpenHarmony 壳工程 │ ├── entry/ │ │ └── src/main/ │ │ ├── ets/ # 原生入口与遗留逻辑 │ │ └── module.json5 │ └── build-profile.json5 └── pubspec.yaml看到 ohos 目录出现的那一刻这个项目才算真正迈出了第一步。2.3 首次构建运行验收工程生成后用 DevEco Studio 打开 ohos 目录配置好签名证书和设备连接直接点击运行。第一次跑通的标准很简单真机上出现一个 Flutter 渲染的页面并且操作响应正常。但第一次构建大概率不会那么顺利。我当时遇到的一个典型问题是 Gradle 插件应用方式导致的构建报错类似“使用 apply script 方式应用 Flutter 插件”这种提示。这个在 Flutter 的 Android 工程里见过没想到 OpenHarmony 壳工程里也会有类似的插件声明问题解决思路倒是通用——检查工程根目录的 settings.gradle 和插件应用方式改成声明式引入即可。另外如果 DevEco Studio 提示签名配置缺失或设备未授权也需要先在“Project Structure / Signing Configs”里完成签名配置。首次跑通之后我通常会做一个快速验收清单Flutter 页面能否正常上屏、热重载是否生效、日志里 Flutter 引擎是否正常初始化。这些确认没问题后面加业务功能就不会老怀疑是环境问题了。3. 喝水提醒核心模块调度策略与原生通道3.1 提醒策略规则、间隔与计算逻辑喝水提醒的核心不是“弹个通知”而是“什么时候弹、怎么算下一次时间”。我采用的规则比较简单用户设定提醒起止时间比如 09:00 到 21:00设定间隔比如 120 分钟系统在这段时间内每隔两小时提醒一次如果用户已经达到当日目标杯数则停止提醒。这个计算逻辑的难点在于边界情况。不能简单用“当前时间加间隔”来算因为要考虑跨天、休息区间、用户手动跳过后的下一次时间。我封装了一个函数来做这件事核心思路是从开始时间出发以间隔为步长生成一个提醒时间序列从中选出第一个晚于当前时间的点。class RemindSchedule { final TimeOfDay startTime; final TimeOfDay endTime; final Duration interval; DateTime nextRemindAfter(DateTime now) { final dayStart DateTime(now.year, now.month, now.day, startTime.hour, startTime.minute); final dayEnd DateTime(now.year, now.month, now.day, endTime.hour, endTime.minute); // 当前时间在时段外直接取今天的开始时间 if (now.isBefore(dayStart) || now.isAfter(dayEnd)) { return dayStart; } // 从开始时间开始按步长扫描 DateTime cursor dayStart; while (cursor.isBefore(dayEnd)) { if (cursor.isAfter(now)) return cursor; cursor cursor.add(interval); } return dayStart.add(const Duration(days: 1)); } }这个函数在每次设置变更、每次记录喝水之后重新计算一次把结果保存下来。特殊情况下比如用户在 20:50 错过了最后一次提醒函数返回的会是第二天的开始时间而不是今天超时的时间点符合预期。实际操作中还有一个细节只算时间点不够还得把“跳过本次提醒”这种用户行为考虑进去。我的做法是在状态里维护一个 skipUntil 时间戳计算下次提醒时如果计算结果早于 skipUntil就继续往后推一个间隔直到晚于 skipUntil。这样可以避免用户点了“跳过”后一分钟又弹出来。3.2 用Cubit管理提醒配置与喝水记录状态管理这块我选了 Cubit 而不是完整的 Bloc原因很简单这个项目的状态逻辑不算复杂没有特别多需要并发响应的异步事件Cubit 更轻代码量更少对新手也更友好。它在 OpenHarmony 上就是一个纯 Dart 库不存在平台适配问题。先说状态设计。整个 App 需要全局共享的状态主要是三块class ReminderState { final bool waterGoal; // 每日目标杯数 final TimeOfDay startTime; // 提醒开始时间 final TimeOfDay endTime; // 提醒结束时间 final Duration interval; // 提醒间隔 final MapString, int dailyRecords; // 日期字符串 - 喝水量 }Cubit 里的操作大致有这些更新目标、更新时段、更新间隔、记录一杯水、重置当日记录。这里比较重要的一点是所有状态修改都要同步触发“下次提醒时间”的计算。我把这个逻辑放在一个辅助函数里在每次 emit 新状态后调用一遍保证任何时候拿到的最新状态都带有正确的提醒计划。class ReminderCubit extends CubitReminderState { ReminderCubit() : super(ReminderState.initial()); void recordOneCup() { final today _todayKey(); final cups (state.dailyRecords[today] ?? 0) 1; final newRecords MapString, int.from(state.dailyRecords) ..[today] cups; emit(state.copyWith(dailyRecords: newRecords)); _reschedule(); } }页面侧只需要context.watchReminderCubit()或直接监听 state在 App 冷启动时先loadFromStorage()把本地数据灌进 Cubit。这个模式在页面切换时不会丢状态本质是因为 Cubit 实例挂在全局和具体页面 Widget 的生命周期无关。3.3 桥接原生能力MethodChannel与EventChannel在 OpenHarmony 上Flutter 和原生的通信方式和 Android 大同小异MethodChannel 用于“从 Dart 调原生”EventChannel 用于“从原生向 Dart 推事件”。这个项目的桥接设计比较清晰MethodChannel调用原生侧显示一条系统通知通知栏提醒EventChannel原生侧在提醒触发时主动通知 Dart 层让界面同步状态Dart 侧统一封装在一个服务类里避免页面里到处散落 MethodChannel 代码class NativeBridge { static const _channel MethodChannel(com.example.water/notification); static const _eventChannel EventChannel(com.example.water/remind_event); static Futurevoid showNotification(String title, String body) async { await _channel.invokeMethod(showNotification, { title: title, body: body, }); } static Streamdynamic onRemindEvent() { return _eventChannel.receiveBroadcastStream(); } }原生侧的工作集中在 OpenHarmony 壳工程里。需要做几件事声明通知相关权限、注册通知渠道、实现 MethodChannel 的 setMethodCallHandler 来处理 showNotification 调用、为 EventChannel 设置 StreamHandler 来发送提醒事件。这些代码写在 ohos 工程的 ArkTS 层用 DevEco Studio 调试时可以直接在原生侧打日志排查通道问题比 Dart 侧方便。事件通道这块稍微绕一些因为 EventChannel 是单向推送Dart 侧要先创建好监听原生侧才发得过来。我在 App 启动时就调用了onRemindEvent()建立订阅后续提醒触发事件一到Dart 侧就更新页面上的“最近提醒时间”同时写入当天记录这样即使用户正停在 App 内也能实时看到变化。4. 数据持久化与页面状态保持4.1 本地存储选型与实现喝水记录和配置必须持久化否则 App 一重启数据全丢这功能就没法用了。Flutter 在 OpenHarmony 上的本地存储方案和官方 Flutter 生态类似主要就是三选一SharedPreferences、文件存储、轻量级数据库。我最终选了文件存储把数据写成一个 JSON 文件放在应用私有目录里。原因有几个首先这项目的数据量很小只有配置项和每天一条喝水记录数据库完全是大材小用其次SharedPreferences 插件在 OpenHarmony 分支上的适配成熟度一般我不想在平台的通道层多踩一个不确定的坑。文件读写是 Dart 语言内置能力不需要任何第三方插件依赖最稳。class LocalStore { final String filePath; FutureMapString, dynamic load() async { final file File(filePath); if (!await file.exists()) return {}; final content await file.readAsString(); return jsonDecode(content) as MapString, dynamic? ?? {}; } Futurevoid save(MapString, dynamic data) async { final file File(filePath); await file.writeAsString(jsonEncode(data)); } }保存的数据结构长这样goalCups、startTime、endTime、intervalMinutes再加上 dailyRecords 这个映射键是“yyyy-MM-dd”值是当天的杯数。每次状态变更就整体写一次文件文件很小性能完全不是瓶颈。唯一要注意的是异步写入的竞态——如果用户快速连续记录多杯水要保证最后一次 emit 的状态是最终保存的不能在写入完成前又覆盖。我的做法是在 Cubit 里每次变更后都调用 save 并传入完整最新状态而不是局部 patch。4.2 每日数据模型与统计进度有了持久化结构接下来要处理的是界面上的统计展示。这个统计逻辑看着简单做的时候有几个想明白的点。我给今日记录设计的模型是“杯数优先”而不是“毫升数优先”。虽然喝水总量更科学但用户在提醒弹窗场景下的操作成本要低点一下“记一杯”比“输入毫升数”体验好太多。真要做精细的话可以在设置里允许用户自定义“一杯多少毫升”展示时换算成总毫升数但存储核心还是以杯数为准。每日统计的核心是当天已经喝了多少杯、距离目标还差几杯、完成百分比是多少。这些全部可以从前面的 dailyRecords 里算出来double progressPercent(int cups, int goal) { if (goal 0) return 0; return min(1.0, cups / goal); }页面上的进度环我用 Flutter 自带的 CustomPaint 画的画圆弧的逻辑很简单关键是动画要做平滑过渡。记录了一杯水之后从 50% 到 62.5% 的圆弧变化如果直接重绘会显得很生硬我加了一个 400 毫秒的隐式动画包装视觉上自然很多。4.3 Navigator切换页面时会丢状态吗这个问题是 Flutter 里被问得特别多的问题放到这个项目里同样重要。用户从“今日统计页”切到“设置页”再切回来统计页的数据如果重新走了一遍初始化就会出现白屏闪烁、状态短暂丢失等问题。实际上Navigator 默认是不丢状态的。页面被 push 覆盖时只是从视图树中摘除但页面对象和它持有的状态对象还活着只要不 pop 销毁回来时数据都在。但有一种情况例外页面内部在initState里做了异步加载而这个异步结果依赖页面 Lifecycle那每次回到页面时如果触发了重建就可能看到加载态。我的做法是让页面成为状态的“消费者”而不是“持有者”。所有数据都放在全局 Cubit 里页面只负责根据 Cubit 状态渲染。这样无论页面怎么跳转、怎么重建只要 Cubit 还活着数据就在。页面切回来时可能画面会闪一下但不会出现数据丢失。真想在页面回到前台时刷新数据可以监听系统侧的事件通知比如通过 EventChannel 在提醒触发事件到达时更新状态这比依赖页面生命周期要可靠得多。5. 常见问题与排查技巧实录5.1 构建与工具链高频踩坑折腾这套环境的过程里构建问题占了很大比重而且很多报错在网上查不到直接答案。我把遇到过的三类典型问题列一下做个速查参考。问题现象常见原因解决思路构建提示 Gradle 插件应用方式错误ohos 壳工程里插件声明方式不兼容修改 settings.gradle 中的插件应用方式改为声明式引入类似 Flutter 官方 Android 工程的插件管理方式Flutter SDK 版本不被当前工具链识别命令行用的 Flutter 和环境变量里的版本不是同一套严格检查where flutter确保指向 OpenHarmony 分支 SDK版本组合以官方文档为准编译失败提示某个第三方 Flutter 包缺少 ohos 实现插件没有适配 OpenHarmony 平台检查插件是否有 ohos 支持没有就换等效方案或者在桥接层自己实现对应能力第一类问题最容易被忽略因为错误信息长且涉及 Gradle 内部逻辑很多人会以为是自己项目配置写错了。实际上就是平台壳工程和 Flutter 插件之间的集成方式差异调整插件声明格式基本就能解决。第三类问题更值得提前预防。选 Flutter 插件时先看它有没有 ohos 目录没有的话基本用不了。像 flutter_local_notifications 这种社区热门插件在 OpenHarmony 分支下的适配不一定完善我的方案就是直接在桥接层用 MethodChannel 自己实现通知绕开了插件限制反而更可控。5.2 运行时与UI兼容问题构建通过只是第一关运行时的问题更隐蔽。我在这个项目里碰到过两个有代表性的问题分享出来供参考。第一个是页面切换动画异常。Flutter 的页面切换默认动画在部分 OpenHarmony 真机上表现不佳偶尔会出现跳变或卡顿。这和 Flutter 的 Impeller 渲染引擎在 OpenHarmony 分支上的兼容性有关渲染层适配还没有做到像 Android 那样成熟的水平。我暂时不追求解决引擎层的问题而是在用户体验上做补偿把不必要的页面切换动画关掉或者用更轻的自定义过渡。实测下来减少动画复杂度之后切换流畅度改善明显。如果你的项目对页面切换动画要求很高建议先在目标设备上做真机验证评估动画是否可接受。第二个是通知权限缺失。在桌面调试时点击记录喝水没问题但设置提醒后一到时间完全没反应看原生日志才意识到是通知权限没申请。这里有个容易漏掉的细节OpenHarmony 侧的应用权限声明和 Android 不同需要在工程的配置文件中添加通知权限声明同时运行时可能需要用户在系统设置里手动确认。我的建议是在设置页加入一个“检查提醒权限”入口首次启动时引导用户完成授权避免功能装好了但触发不了这种尴尬场景。5.3 后台提醒可靠性与电量优化这个项目做的是生活助手类应用用户大概率会切到后台甚至锁屏所以提醒能不能准点触发是决定成败的细节。但我也要说句实在话纯 Flutter 层面的 Timer 在应用进入后台后并不可靠特别是 OpenHarmony 这种对后台任务有管控的系统。我的方案是分场景处理。App 在前台时用 Dart 层 Timer 做准点提醒响应快、体验顺滑代码也不用跨桥。App 进入后台或锁屏后把提醒调度能力放到原生层利用系统级的通知调度能力来触发。实现上Dart 侧一收到生命周期变化事件就把计算好的下一次提醒时间传给原生层原生层负责在系统侧挂提醒。等提醒触发原生层通过 EventChannel 把事件回传Dart 侧再补记杯数和刷新 UI。这个方案在电量表现上也算合理前台 Timer 和后台系统调度各管各的时间段不存在双重唤醒。即使系统对后台调度做了限制至少在前台场景下功能是完整可用的不会因为后台限制而显得不可用。5.4 跨端生态版本差异的提醒最后补充一个不只针对 OpenHarmony 的普遍问题Flutter 生态的版本差异。写代码时如果打开网络上的 Flutter 教程很多方案默认跑的是某个特定版本换到 OpenHarmony 分支上往往细节对不上。比如有的包要求最新版 Dart 语法但 OpenHarmony 分支的 Flutter SDK 版本相对滞后就可能导致一堆依赖报版本低。所以在给项目选依赖包时我习惯去 pub.dev 看一眼包的历史版本选一个和当前 SDK 兼容性最好的而不是无脑最新版。这个习惯帮我省了很多莫名其妙的上手时间。6. 一点补充的想法做这个项目最大的感受是OpenHarmony 上写 Flutter 应用最大的成本不在写业务代码而在环境适配和原生桥接。业务层几乎可以做到零修改移植过来真正花时间的是把通知、权限、后台调度这些系统能力一个一个趟明白。如果你也准备做类似的事我的建议是第一保持 Dart 业务层干净把一切涉及系统能力的调用都收口到一个桥接服务里将来换平台只改桥接层第二在做功能规划时留出原生联调的时间不要假设插件一定可用第三先在真机上跑通最小闭环再做完整功能环境问题的排查速度会快很多。这个喝水提醒功能只是整套生活助手 App 的一个模块后续如果要加“运动步数同步”“体重趋势图表”这些能力架构上完全可以直接吃下状态管理用 Cubit 扩展新的领域模块系统能力继续走 MethodChannel / EventChannel 桥接数据层增加对应的存储结构就行。走到这一步项目的地基算是打稳了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

开题报告总被导师打回来?毕夏AI官网帮你搞懂它到底在审什么 2026/9/29 21:04:16

开题报告总被导师打回来?毕夏AI官网帮你搞懂它到底在审什么

毕夏AI官网 www.bixiaai.com 毕夏AI写作官网 www.bixiaai.com 毕夏官网 www.bixiaai.com 毕夏智能写作官网 www.bixiaai.com 先讲一个真实的故事 我认识一个研二的学生,开题报告被打回来四次。 第一次,导师说“研究问题不聚焦”。第二次&#xff…

阅读更多 →
基于BW16+ESP32-CYD的无线EEG原型链路设计与实战调优 2026/9/29 21:04:16

基于BW16+ESP32-CYD的无线EEG原型链路设计与实战调优

1. 这条链路到底在解决什么真实问题?——从实验室脑电设备说起你有没有见过医院或高校实验室里那些动辄几十万的EEG设备?头戴式电极帽、专用放大器、屏蔽室、同步触发线、配套软件……整套系统像一台精密仪器,但代价是:它根本没法…

阅读更多 →
Java的初步认识 2026/9/29 21:04:16

Java的初步认识

1.Java语言概述1.1 Java是什么Java是一种优秀的程序设计语言,Java还是一个有一系列计算机软件和规范形成的技术体系。1.2 Java的种类JavaSE (Java Standard Edition): 1. 核⼼: Java的基础平台 2. ⽤途: 开发桌⾯应⽤和简单服务器程序 3. 主要内容: 核⼼语⾔特性、基…

阅读更多 →
2026年专访杭州亨得利售后:哪些腕表养护项目不建议盲目做? 2026/9/29 21:04:16

2026年专访杭州亨得利售后:哪些腕表养护项目不建议盲目做?

引言杭州地处江南,梅雨季湿度高,常年温润多雨,本地表主在腕表佩戴与养护上面临着和北方城市截然不同的环境挑战。很多腕表爱好者在社交平台看到各类腕表养护推荐,从深度清洗、表壳抛光到机芯油泥清洁,五花八门的项目让…

阅读更多 →
基于Claude的SKILL原理梳理:SKILL.md、Frontmatter与allowed-tools配置笔记 2026/9/29 21:04:16

基于Claude的SKILL原理梳理:SKILL.md、Frontmatter与allowed-tools配置笔记

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

阅读更多 →
装了最近爆火的 Hermes,和 OpenClaw 的对比来了!TaoToken 统一 Key 接入实测 2026/9/29 21:03:57

装了最近爆火的 Hermes,和 OpenClaw 的对比来了!TaoToken 统一 Key 接入实测

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

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉