HarmonyOS实例总复习:算术大闯关串联声明式UI与状态管理
HarmonyOS应用实例走到第60个总复习我选了“算术大闯关”当收尾。表面看这就是一个四则运算答题游戏选难度、出题、点选项、倒计时、扣命、结算。但拆开看它把声明式UI、状态管理、页面路由、本地持久化、生命周期串成了一整条链路。如果你已经跟着前面几十个实例敲过不少页面但总觉得知识点是散的这个项目就是最好的缝合练习哪怕你刚起步把它当目标驱动型小项目来做也完全能上手。这个项目的好处在于不依赖后端、不需要账号体系、不引入额外复杂框架却能把一个应用从“入口页面”到“业务逻辑”到“结果落盘”完整走一遍。做完之后你收获的不只是一个能演示的小游戏而是对HarmonyOS应用工程结构的整体手感。1. 为什么选“算术大闯关”做总复习1.1 一个小游戏藏了哪些必须复习的知识点如果只是按前面几十个实例的节奏做单个登录页、单个列表页每个知识点都见过但连起来就卡壳。算术大闯关正好把最常见的几个点全部揉进了同一个应用里声明式UI布局首页、答题页、结算页三个页面涉及Column、Row、Button、Text、Progress等基础组件的组合。状态管理得分、生命值、当前题目、倒计时、当前关卡都是页面内高频变化的UI状态必须用响应式变量驱动。页面路由从首页进答题页答题结束进结算页需要传参和替换页面栈。本地持久化历史最高分要保存下来下次启动还能读到。生命周期与定时器倒计时涉及定时器创建、恢复、销毁正好把onPageShow、onPageHide、aboutToDisappear这些平时容易忽略的生命周期全部用上。单独看每一块都不复杂但组合起来就能逼你思考“这个状态应该放在哪个页面”“这个数据什么时候写盘”“这个定时器什么时候清理”。这些问题正是从“会写单页面Demo”走向“能做一个完整小应用”必须迈过的坎。1.2 适合谁来读需要什么基础我建议两类读者重点关注这个项目。一类是已经学过基础组件、会写简单页面但没做过完整应用的人。你不需要掌握多高深的知识只要用过页面路由、知道State是什么就能跟着把流程走完。另一类是正在做一个功能更复杂的应用但被状态管理和页面通信折磨过的人。算术大闯关体量小正好适合用来把路由参数、页面刷新、数据持久化这几个问题的边界理清楚。前置基础其实就三条会创建HarmonyOS工程知道Entry和Component的作用能看懂基础的ArkTS语法。看不懂也没关系我会把每一段代码为什么这么写都讲清楚。2. 总体设计页面、状态、数据各归其位2.1 模块划分三个页面加两个工具文件动手写代码之前先别急着堆页面。我习惯把所有功能拆成职责单一的文件哪怕是小项目也一样。这个项目我拆成了五个主要部分模块职责关键技术点Index页面选择难度、展示历史最高分、开始闯关页面生命周期、路由pushUrlQuizPage页面出题、答题、倒计时、判分、维护生命值State、定时器、路由replaceUrlResultPage页面展示结果、显示本局得分和通关状态路由参数读取QuestionGenerator工具按难度生成题目、保证答案合理、生成四个选项随机数、集合去重GameStorage工具最高分读取和写入Preferences持久化这样划分之后每个文件都能独立看、独立测。题目生成逻辑不依赖任何UI组件跑在纯业务代码里存储逻辑也被抽出来页面只需要调用“读最高分”和“存最高分”两个函数。后面如果发现问题定位起来非常快。2.2 状态管理方案先用局部状态再补全局状态在HarmonyOS的声明式开发里最容易被问到的就是“这个变量到底该用哪种状态”。我给自己定了一个很简单的判断顺序如果一个状态只在当前页面使用答题页的得分、倒计时、当前题目用State修饰在页面内部就好。如果一个页面需要通知另一个页面答题结束时把得分传给结算页用路由参数。如果多个页面都需要读同一份数据比如最高分在首页和结算页都要显示可以配合AppStorage全局存储底层再持久化到Preferences。如果数据必须跨越应用生命周期重启之后还要存在就一定要用Preferences或数据库。算术大闯关里真正必须跨页面共享的就是“本局得分”“当前关卡”“是否通关”这几个一次性参数直接用路由传递最干净。最高分是长期数据走Preferences。其余状态全部是页面内局部状态没有设计跨页面同步的复杂场景。这个方案不是最花哨的但它是体量最小的可靠方案。对一个答题小游戏来说硬上一套全局状态管理反而不容易维护。2.3 不盲目上架构靠“文件职责”控制复杂度有人可能觉得项目都做总复习了是不是该用ViewModel、仓库模式之类的架构我的看法是不要教条。架构的目的是控制复杂度。算术大闯关的核心复杂度集中在两处题目生成规则和倒计时生命周期。这两个问题靠“职责拆分”就够了题目生成放进独立工具倒计时收敛成startTimer和stopTimer两个方法页面本身只负责绑定状态和响应事件。我在实际练习中体会很深的一点是小项目最怕的不是代码写得“不够架构”而是为了迎合某种架构把三行能写清楚的逻辑拆成八个文件最后反而没人看得懂。先把这个项目的每个文件职责理清楚等以后要做更复杂的应用再自然引入架构模式会更顺。3. 核心实现出题、答题、倒计时3.1 先定义Question对象我习惯先把数据的形状定下来再写页面。题目对象需要包含四样东西题面文本、正确答案、四个选项、当前难度。其中难度字段在计分时要用到和选项一起放进对象里页面逻辑会更简洁。// model/Question.ets export class Question { text: string; answer: number; options: number[]; difficulty: number; constructor(text: string, answer: number, options: number[], difficulty: number) { this.text text; this.answer answer; this.options options; this.difficulty difficulty; } }为什么不直接用interface因为题目对象在整个流程里只有构造和读取没有动态扩展用class带构造器反而更直观也能在构造时保证四个字段都齐。实际项目里如果后面要给题目加“题目类型”“解析文本”在这个类里加字段就行影响的代码面非常小。3.2 题目生成器随机、防重复、防退化题目生成是整个项目的“隐藏难点”。表面看起来就是随机生成数字和运算符但真正写起来会遇到三个问题第一减法结果不能总是负数。低难度关卡里用户可能是不太熟悉负数的小朋友所以简单模式里的减法要保证大数减小数。第二选项必须防重复。如果正确答案是10干扰项又生成了10四个选项里会出现两个相同答案用户就会懵。第三选项的位置要随机不能永远把正确答案放在第一个或者最后一个否则用户不用算题直接找位置就能蒙对。下面这段生成器代码就是这么设计的// utils/QuestionGenerator.ets import { Question } from ../model/Question; function randInt(min: number, max: number): number { return Math.floor(Math.random() * (max - min 1)) min; } function shuffle(list: number[]): number[] { let result list.slice(); // 够用即可不追求加密级随机只要位置不固定 result.sort(() Math.random() - 0.5); return result; } function createOptions(correct: number): number[] { let options: Setnumber new Setnumber(); options.add(correct); // 只要凑满4个不重复选项就停 while (options.size 4) { let offset randInt(2, Math.max(5, Math.abs(correct) 3)); let wrong randInt(0, 1) 0 ? correct offset : correct - offset; if (wrong ! correct) { options.add(wrong); } } return shuffle(Array.from(options)); } export function createQuestion(level: number): Question { let a: number 0; let b: number 0; let answer: number 0; let text: string ; if (level 1) { // 简单20以内加减减法保证非负 a randInt(1, 20); b randInt(1, 20); if (randInt(0, 1) 0) { text ${a} ${b}; answer a b; } else { if (a b) { let temp a; a b; b temp; } text ${a} - ${b}; answer a - b; } } else if (level 2) { // 中等一半概率乘法表一半概率两位数加法 if (randInt(0, 2) 0) { a randInt(2, 9); b randInt(2, 9); text ${a} × ${b}; answer a * b; } else { a randInt(50, 200); b randInt(10, 50); text ${a} ${b}; answer a b; } } else { // 困难两位数乘个位数或者构造整除除法 if (randInt(0, 1) 0) { a randInt(11, 99); b randInt(2, 9); text ${a} × ${b}; answer a * b; } else { b randInt(2, 9); answer randInt(11, 99); a b * answer; text ${a} ÷ ${b}; } } return new Question(text, answer, createOptions(answer), level); }有几个细节特意处理过干扰项偏移量不是固定值而是跟着答案大小动态调整。如果答案是100干扰项只偏移1或2一眼就能看出是错的游戏就太简单如果答案是5偏移量太大干扰项明显不合理。除法采用“先定商和除数再反推出被除数”的方式保证一定整除不会出现除不尽的式子。所有选项在返回前都会打乱顺序正确答案不会固定出现在某个位置。这套生成器虽然没有覆盖极复杂的出题规则但对一个闯关游戏来说已经把用户体感上的“坑”都填上了。3.3 答题页的状态流转与判分逻辑答题页是这个项目状态最密集的地方。需要维护的状态有当前题目、得分、生命值、当前关卡、本关答对数、是否正在判分、剩余秒数。// pages/QuizPage.ets import { Question } from ../model/Question; import { createQuestion } from ../utils/QuestionGenerator; import router from ohos.router; Entry Component struct QuizPage { State question: Question createQuestion(1); State score: number 0; State life: number 3; State level: number 1; State correctInLevel: number 0; State isAnswering: boolean false; State timeLeft: number 15; timerId: number -1; aboutToAppear(): void { let params router.getParams() as Recordstring, number; if (params params[difficulty]) { this.level params[difficulty]; } this.question createQuestion(this.level); this.startTimer(); } aboutToDisappear(): void { this.stopTimer(); } startTimer(): void { this.stopTimer(); this.timeLeft 15; this.timerId setInterval(() { this.timeLeft--; if (this.timeLeft 0) { this.handleTimeout(); } }, 1000); } stopTimer(): void { if (this.timerId ! -1) { clearInterval(this.timerId); this.timerId -1; } } handleTimeout(): void { if (this.isAnswering) { return; } this.isAnswering true; this.stopTimer(); this.life--; setTimeout(() this.nextQuestion(), 800); } chooseAnswer(index: number): void { if (this.isAnswering) { return; } this.isAnswering true; this.stopTimer(); let isCorrect this.question.options[index] this.question.answer; if (isCorrect) { this.score this.level * 10; this.correctInLevel; } else { this.life--; } setTimeout(() this.nextQuestion(), 800); } nextQuestion(): void { this.isAnswering false; // 生命归零直接失败 if (this.life 0) { this.goResult(false); return; } // 本关答对10题后进入下一关或通关 if (this.correctInLevel 10) { if (this.level 3) { this.goResult(true); return; } this.level; this.correctInLevel 0; } this.question createQuestion(this.level); this.startTimer(); } goResult(isWin: boolean): void { this.stopTimer(); router.replaceUrl({ url: pages/ResultPage, params: { score: this.score, level: this.level, isWin: isWin } }); } build() { Column({ space: 16 }) { // 顶部信息区 Row({ space: 12 }) { Text(第${this.level}关) Text(本关${this.correctInLevel}/10) Text(得分 ${this.score}) Text(生命 ${this.life}) } .margin({ top: 20 }) // 题目区 Text(this.question.text) .fontSize(40) .fontWeight(FontWeight.Bold) .margin({ top: 40, bottom: 40 }) // 四个选项 ForEach(this.question.options, (option: number, index: number) { Button(option.toString()) .width(70%) .height(48) .onClick(() this.chooseAnswer(index)) }) // 倒计时条 Progress({ value: this.timeLeft, total: 15 }) .width(70%) .margin({ top: 30 }) } .width(100%) .height(100%) } }这段代码里有几个地方值得重点讲。首先是isAnswering这个“锁”。如果没有它用户在极短时间内点两次选项第一下已经触发判分第二下又会进入逻辑导致生命值重复扣除或者题目跳过。锁一加上判分期间所有点击全部忽略等nextQuestion再解锁。其次是“本关答对数”而不是“总答对数”。如果只看总得分判断是否通关会出现我一开始设计时踩到的坑从第一关到第三关得分已经超过通关阈值导致第三关刚答一道题就误判通关。后来改成correctInLevel单独统计每关答对数量当本关答对达到10题时要么升关要么通关逻辑才真正符合“闯关”的感觉。最后是setTimeout的延迟。判分之后先停800毫秒再进入下一题是为了给用户一个看到“答对了还是答错了”的反馈时间。如果你想让体验更精细可以在这800毫秒里给选项按钮设置对错颜色这个项目里我根据实际需要加了判分体验会好很多。3.4 倒计时组件一个方法解决所有清理问题倒计时在答题页面里是最容易翻车的部分。很多初学者会在页面里到处写setInterval结果页面跳走了、应用切后台了定时器还在跑倒计时变成负数生命值莫名其妙扣光。我的处理原则是定时器的创建和销毁全部收敛到startTimer和stopTimer两个方法里其他任何地方都不要直接调用clearInterval。看代码里的几个调用点aboutToAppear里启动aboutToDisappear里停止答完题停超时停跳转结算页之前停。无论哪一种情况最终都走到stopTimer这一个出口。这样排查问题的时候只需要看这个出口有没有被执行大大降低定位难度。4. 路由与持久化把三个页面串成完整应用4.1 pushUrl 和 replaceUrl 到底怎么配合这个项目里有两个跳转场景用到的路由方法不一样。首页到答题页用router.pushUrl。这是因为从答题页还可能返回首页pushUrl会保留首页在页面栈里用户按系统返回键时能正常回去。答题页到结算页我特意用router.replaceUrl。如果用pushUrl页面栈会变成“首页、答题页、结算页”用户按返回键会从结算页回到答题页但答题页此时已经处于一个半终止状态还得处理“点按钮继续答题”之类的残留逻辑。用replaceUrl替换掉答题页页面栈变成“首页、结算页”返回键只能回到首页逻辑干净很多。这里的经验是不是所有跳转都无脑用pushUrl。跳过去之后还要回来的用pushUrl跳过去之后不希望用户再回到上一页的用replaceUrl。4.2 Preferences保存最高分重置应用也不丢最高分属于“哪怕用户退出应用再打开也要存在”的数据必须落盘。在HarmonyOS里体量小的键值对数据用Preferences就够不需要上数据库。// utils/GameStorage.ets import { preferences } from kit.ArkData; import { common } from kit.AbilityKit; const PREFERENCES_NAME math_game_demo; const KEY_BEST_SCORE best_score; export async function getBestScore(context: common.UIAbilityContext): Promisenumber { let pref await preferences.getPreferences(context, PREFERENCES_NAME); let value await pref.get(KEY_BEST_SCORE, 0); return value as number; } export async function saveBestScore(context: common.UIAbilityContext, score: number): Promisevoid { let pref await preferences.getPreferences(context, PREFERENCES_NAME); let current await pref.get(KEY_BEST_SCORE, 0) as number; if (score current) { await pref.put(KEY_BEST_SCORE, score); await pref.flush(); } }注意这里保存的时候做了“只有当前分数大于历史最高分才写入”的判断。这个判断放在存储工具里比放在页面里更合理因为页面不需要关心“这局成绩是否打破了纪录”它只要把本局得分传到存储层就行。这里有个细节常被忽略preferences.put之后一定要调用flush数据才会真正落盘。只调put内存里改了但应用一旦被杀掉就可能丢失。这个坑我在早期的练习里遇到过一次后来凡是写Preferences写完必flush。4.3 返回首页刷新最高分关键在onPageShow首页显示历史最高分这个最高分在结算页可能被更新。问题是从结算页返回首页时首页已经存在过不会重新执行aboutToAppear。如果你只在aboutToAppear里读最高分就会发现成绩永远停留在打开应用时的旧值。解法是使用页面级生命周期onPageShow。只要页面重新出现在前台不管是首次进入还是从其他页面返回都会触发它在onPageShow里重新读取最高分并刷新UI。// pages/Index.ets 中的关键片段 Entry Component struct Index { State bestScore: number 0; State difficulty: number 1; aboutToAppear(): void { this.refreshBest(); } onPageShow(): void { this.refreshBest(); } async refreshBest(): Promisevoid { let context getContext(this) as common.UIAbilityContext; this.bestScore await getBestScore(context); } startGame(): void { router.pushUrl({ url: pages/QuizPage, params: { difficulty: this.difficulty } }); } build() { Column({ space: 24 }) { Text(算术大闯关) .fontSize(36) .fontWeight(FontWeight.Bold) .margin({ top: 60 }) Text(历史最高分${this.bestScore}) .fontSize(18) Row({ space: 12 }) { Button(简单) .onClick(() { this.difficulty 1; }) Button(中等) .onClick(() { this.difficulty 2; }) Button(困难) .onClick(() { this.difficulty 3; }) } Button(开始闯关) .width(60%) .onClick(() this.startGame()) } .width(100%) .height(100%) } }getContext(this)拿到的是当前UI组件的Context在Entry组件里可以正常使用。页面里需要同时处理“首次进入刷新”和“从子页面返回刷新”两个场景时onPageShow就是最佳出口这也是这个小项目里很好的一课。5. 完整流程串通工程结构、配置与验收5.1 推荐的目录结构当所有代码写完之后完整的工程结构大概长这样entry/src/main/ets/ ├── entryability/ │ └── EntryAbility.ets ├── pages/ │ ├── Index.ets │ ├── QuizPage.ets │ └── ResultPage.ets ├── model/ │ └── Question.ets └── utils/ ├── QuestionGenerator.ets └── GameStorage.etsEntryAbility是Ability生命周期入口小型项目中一般不需要改动。pages目录放三个页面。model放数据模型utils放纯业务逻辑工具。这样划分后就算是一个新手打开工程也能第一时间知道“什么东西该去哪儿找”。5.2 新建工程时最容易出错的配置点用IDE新建工程后很多时候直接跑起来会白屏或者路由找不到页面主要原因是页面路径没有注册。HarmonyOS的路由页面需要维护在main_pages.json文件里路径以pages/开头不需要写.ets后缀。{ src: [ pages/Index, pages/QuizPage, pages/ResultPage ] }新建三个页面文件之后第一件事就是确认这个文件里有没有把新页面加进去。我见过不少朋友在页面跳转时报“路由找不到”排查半天发现是这里漏了注册。本项目不涉及网络、相机、位置等敏感权限所以module.json5里不需要申请任何权限。这一点对新手很友好少了一大堆权限配置的干扰。5.3 验收清单怎么判断这个Demo真的做完了代码全都写完、能编译通过不代表项目做完了。我建议至少跑一遍下面这个验收清单操作期望结果首次启动应用查看首页历史最高分为0能选择难度选择“简单”并点击开始进入答题页第一题为已完成注册的关卡难度连续答对10题本关进度达到10后自动进入下一关题目变难答错一次生命值从3变为2题目自动刷新倒计时归零按答错处理生命值减少一生命值降为0跳到结算页显示失败结果在困难难度下答对10题跳到结算页显示通关结果结束一局后返回首页首页最高分刷新为新纪录关闭应用重新打开历史最高分仍然保留在答题页反复按返回键不会回到已经失效的答题页只剩首页和结算页的合理栈这份清单覆盖了路由、状态、持久化、生命周期这几个核心点。全部通过这个“总复习”项目才算真正落地。6. 我踩过的坑常见问题与排查实录6.1 问题速查表把这个项目里最常遇到的问题整理成了表格方便对照排查现象常见原因解决办法返回首页后最高分不更新只用了aboutToAppear没有用onPageShow在首页添加onPageShow重新读取Preferences切到后台再回来倒计时已经归零定时器没有跟随页面隐藏暂停onPageHide时停止定时器onPageShow时重新启动快速连续点击多个选项生命值乱扣缺少应答锁增加isAnswering状态判分期间忽略点击四个选项里出现相同答案或者正确答案总在固定位置生成器没有去重、没有打乱用Set去重返回前shufflePreferences写入后重启丢失put之后没有flushput完成后显式调用flush结算页按返回键会回到答题页用pushUrl跳到结算页换成replaceUrl替换掉答题页分数快满时提前通关用总分判断通关误判按“本关答对数”判断通关而不是总分这里每一条我都在实际调试过程里遇到过也看到过身边的朋友重复踩。把这个表收藏起来等你写出类似的闯关项目时能省掉不少排查时间。6.2 定时器和生命周期这个项目最值得反复琢磨的地方倒计时是这个项目里“看起来简单、做起来烦”的典型问题。我最早写第一版时只在答完题之后清理定时器结果遇到两个场景场景一用户在答题时切到后台。系统不会自动帮你清掉setInterval倒计时依然在走等用户切回来时间早就归零直接判错扣命。场景二用户从答题页返回首页。aboutToDisappear里没有清理定时器页面虽然不可见了但定时器还在跑之后还可能因为回调修改已经销毁页面的状态状态混乱。后来的处理方式是双保险onPageHide里也调用stopTimeronPageShow里再调用startTimeraboutToDisappear里再补一刀。虽然看上去多点了几行代码但换来的是“无论怎么切页面定时器状态都可控”。这里还有一个细节setInterval的返回值在ArkTS里是number保存到组件成员变量timerId里清理时只需要判断这个值不等于初始值就能安全clearInterval。不要每次新建定时器都直接赋值先停掉旧定时器避免多个定时器叠加。6.3 调试心得状态提升到底帮我省了什么最后说一个方法论层面的体会。这个项目里我一开始把题目生成逻辑直接写在QuizPage里页面里全是随机数和Set操作看起来也能跑但调试起来非常痛苦。后来我把题目生成拆到QuestionGenerator把分数读写拆到GameStorage页面里剩下的就是状态和事件响应。这个“状态提升”和“逻辑下沉”的调整收益非常明显。出题有问题不用打开页面代码直接看QuestionGenerator就能定位最高分不刷新直接检查GameStorage和首页onPageShow。页面代码越薄调试成本越低。如果你也在做类似的小游戏项目我的建议是别让你的页面成为“大杂烩”把能独立测试的核心逻辑全部抽出去。这个习惯比多写十几个页面更能提升你的工程能力。这个项目最值钱的练习不是多刷了几道算术题而是把分散的知识点拼成一条能跑通的链路。做完它我自己对生命周期和定时器的理解都被刷新了一遍。最后分享一个小技巧凡是和定时器有关的页面把startTimer和stopTimer收敛成两个方法所有恢复、结束、销毁都从这两个出口走不要到处散落clearInterval。这个习惯让我在后续的页面里少踩了至少一半的坑。

相关新闻

npm error code 128 详解:Git 依赖拉取失败的排查与解决

npm error code 128 详解:Git 依赖拉取失败的排查与解决

1. 问题会面:npm error code 128 到底在说什么先说我自己的遭遇。某天我拿到一个 OpenClaw 相关的项目包,在 Windows 环境下执行npm install,依赖下载到一半,直接给出一段让人头皮发麻的报错:npm error code 128 npm e…

2026/10/16 12:42:18 阅读更多 →
DeepSeek V3 + AnythingLLM 本地知识库搭建实战:文档不出本地的 RAG 方案

DeepSeek V3 + AnythingLLM 本地知识库搭建实战:文档不出本地的 RAG 方案

简介:这份PDF教程面向希望搭建个人知识库的知识管理爱好者与效率工具用户,以DeepSeek V3为核心,讲解从零构建本地化知识库的完整流程。内容涵盖注册DeepSeek账号并获取API密钥、安装AnythingLLM客户端、配置AI提供商与模型选择、创建工作区、…

2026/10/16 12:42:18 阅读更多 →
动态环境下视觉SLAM与SfM综述:原理、挑战与工程实践

动态环境下视觉SLAM与SfM综述:原理、挑战与工程实践

1. 为什么动态环境至今还是SLAM的“老大难”做视觉SLAM和SfM(运动恢复结构)的人,大部分时间其实都在跟“静态世界假设”打交道。经典算法从原理上就默认场景是静止的——特征点提取、三角化、姿态估计、回环检测,整条链路都建立在…

2026/10/16 12:42:18 阅读更多 →

最新新闻

征程6M部署YOLOv8s实战:量化、算子适配与板端推理全流程

征程6M部署YOLOv8s实战:量化、算子适配与板端推理全流程

1. 为什么要在征程6M上折腾YOLOv8s把YOLOv8s塞进地平线征程6M,这件事听起来像是把一台家用轿车的发动机装进卡丁车——参数上不是不能跑,但要让它在有限算力下跑出该有的帧率和精度,中间要填的坑比想象中多得多。征程6M这颗芯片的定位是面向中…

2026/10/16 13:17:19 阅读更多 →
AI编程Memory工程实战:用AGENTS.md构建持久化项目记忆

AI编程Memory工程实战:用AGENTS.md构建持久化项目记忆

1. 从无状态到有状态:AI 编程范式转换的底层逻辑 1.1 为什么“无状态模型”正在成为瓶颈 过去两年,大多数人使用 AI 编程的方式非常原始:打开一个对话框,把代码片段贴进去,问一句“帮我改改”,拿到结果&am…

2026/10/16 13:17:19 阅读更多 →
AI编程IDE实操:Java开发环境配置全流程与避坑指南

AI编程IDE实操:Java开发环境配置全流程与避坑指南

老开发最烦的几件事里,必然有“帮新人配环境”这一项。JDK、Maven、Gradle、环境变量、编码格式、镜像源,每一层都能出幺蛾子,而且报错信息永远像是用文言文写的。最近圈子里讨论度很高的一款AI编程IDE,就是冲着解决这类“琐碎但致…

2026/10/16 13:17:19 阅读更多 →
助老志愿管理平台开发实战:Spring Boot+Vue全栈设计

助老志愿管理平台开发实战:Spring Boot+Vue全栈设计

1. 内容整体设计与需求拆解接手这样一个助老志愿管理平台时,我首先关注的不是代码,而是需求本身。社区助老这个场景,核心痛点往往不是“功能不够多”,而是“信息不对称”和“服务过程不可控”。老人有需求不知道找谁,志…

2026/10/16 13:17:19 阅读更多 →
CDH 6.1.0集成Kylin:CM Parcel方案与多租户HBase隔离实践

CDH 6.1.0集成Kylin:CM Parcel方案与多租户HBase隔离实践

1. 项目概述:在CDH 6.1.0生态中集成Kylin的现实意义与典型误区“CDH6.1.0后安装Kylin(麒麟)”这个标题看似是一条技术操作指令,实则指向一个在企业级大数据平台演进过程中反复出现、却常被低估复杂度的关键集成场景。我接触过二十…

2026/10/16 13:17:18 阅读更多 →
鸿蒙开发异步并发:事件循环、Promise、TaskPool与Worker详解

鸿蒙开发异步并发:事件循环、Promise、TaskPool与Worker详解

我第一次在真机上把列表页滑到卡成PPT的时候,说实话还挺意外的。代码看着一点毛病没有,就是在一个点击回调里同步处理了一批图片的下载和解码,结果整个页面僵住了一两秒。后来才反应过来,鸿蒙开发的异步并发压根不是“进阶知识点”…

2026/10/16 13:16:18 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* 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 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →