鸿蒙JS FA入门实战:猜数字游戏开发全流程

发布时间:2026/10/15 8:15:53
鸿蒙JS FA入门实战:猜数字游戏开发全流程 1. 从零上手为什么选猜数字游戏作为JS FA应用的第一个练手项目接触鸿蒙应用开发的朋友在啃完环境搭建和基础概念之后普遍会卡在同一个地方文档看了一堆组件也认了个脸熟但真让自己从零写一个能跑起来的东西脑子里还是一团浆糊。我当初也是这个状态后来发现破局的关键就一条——找一个足够小、但又能把核心链路串起来的项目练手。猜数字游戏恰好就是这么一个东西。它小到什么程度整个应用就一个页面没有网络请求没有数据持久化没有复杂的路由跳转。但它又足够完整有UI布局、有状态管理、有事件绑定、有逻辑判断、有用户交互反馈。换句话说一个JS FA应用最核心的那几根骨架它全占了。你把它写一遍等于把声明式UI的写法、状态变量的驱动机制、点击事件的绑定方式全部过了一遍手。这比看十篇概念文档都管用。这里说的JS FA指的是鸿蒙早期版本中基于JavaScript语言开发FAFeature Ability的一种方式。它的写法跟现在主流的ArkTS有区别但底层思想是一脉相承的——都是声明式UI都是数据驱动视图更新。如果你手头参考的教程或项目模板是JS FA的那用猜数字游戏来入门完全没问题核心概念学会了后面切到ArkTS也是平滑过渡。这篇文章我会把整个开发过程拆开揉碎从项目结构、页面布局、状态设计、逻辑实现到调试技巧每一步都讲清楚为什么这么做、不这么做会怎样。适合刚接触鸿蒙开发、想找一个能跑通全流程的小项目来练手的朋友。代码我会给完整的但更重要的是背后的思路——你理解了思路换个游戏、换个功能照样能自己写出来。2. 动手之前的准备工作项目结构与环境确认2.1 创建项目时容易忽略的几个选项在开发工具里新建一个JS FA项目模板选择那一栏通常会有好几个选项。很多人随手选一个默认的就开始写了结果发现目录结构跟教程对不上。我的建议是选Empty Ability模板语言选JS设备类型按你实际调试的设备来勾选。这样生成的目录最干净没有多余的示例代码干扰。创建完成后你会看到项目根目录下有一个entry模块展开之后重点关注src/main/js这个路径。这里面就是我们的主战场。默认模板会生成一个default目录里面包含pages文件夹和app.js文件。pages文件夹下有一个index目录里面是index.hml、index.js、index.css三个文件。这三个文件分别对应页面结构、页面逻辑和页面样式是JS FA应用最基础的组成单元。注意不同版本的开发工具生成的目录结构可能略有差异有的版本会把pages直接放在js目录下有的会多一层default。以你实际生成的为准核心是找到那三个同名文件。2.2 三个核心文件各自的职责边界刚接触的时候很容易把逻辑写到HML里去或者把样式写在JS里虽然有时候也能跑但后期维护会非常痛苦。我习惯把这三个文件的职责分得很清楚HML文件只负责页面长什么样。有哪些组件、怎么嵌套、绑定哪些事件和属性全部在这里声明。不写任何计算逻辑。JS文件只负责数据和逻辑。页面上要显示什么数据、用户操作之后数据怎么变、变化之后怎么通知页面刷新全部在这里处理。CSS文件只负责样式。颜色、大小、间距、布局方式全部在这里定义。这么分工的好处是当你发现页面显示不对时只需要去HML里找结构问题数据不对时只需要去JS里找逻辑问题。排查范围一下子就缩小了。2.3 调试环境的确认在开始写代码之前先确保你的预览器或者模拟器能正常跑起来默认模板。点击运行按钮如果能看到默认页面显示出来说明环境没问题。这一步看起来多余但我见过太多人上来就改代码改了半天发现是环境本身就没配好白白浪费时间。如果你用的是真机调试需要提前在设备上开启开发者模式并完成授权。具体操作跟设备型号有关这里不展开核心是确保设备能被开发工具识别到。3. 猜数字游戏的页面布局用HML搭出交互骨架3.1 先想清楚页面上需要哪些元素在动手写HML之前我习惯先在纸上画一下页面大概长什么样。猜数字游戏需要哪些东西一个标题告诉用户这是个什么游戏。一段提示文字显示当前的范围或者上一轮猜测的结果反馈。一个输入框让用户输入猜测的数字。一个按钮用户输入完之后点击提交。一个重新开始的按钮游戏结束后可以重置。就这些。不需要花哨的布局垂直排列下来就行。想清楚这些之后HML的结构就呼之欲出了。3.2 HML代码的逐段拆解先看完整的HML结构div classcontainer text classtitle猜数字游戏/text text classhint{{ hintText }}/text input classguess-input typenumber placeholder输入你猜的数字 onchangeonInputChange / button classbtn-guess onclickonGuess确认猜测/button button classbtn-reset onclickonReset重新开始/button /div最外层用一个div作为容器class设为container方便后面用CSS统一控制布局。里面依次放了标题、提示文字、输入框和两个按钮。提示文字那里用了{{ hintText }}这种写法这是数据绑定的语法。花括号里的变量名对应JS文件里data对象中的一个属性。当这个属性的值发生变化时页面上显示的文字会自动更新不需要手动去操作DOM。这是声明式UI最核心的便利之处。输入框的type设为number这样在某些设备上会弹出数字键盘用户输入更方便。onchange绑定了一个叫onInputChange的方法用户每次修改输入内容时都会触发。按钮上的onclick分别绑定了onGuess和onReset两个方法对应猜测和重置两个操作。3.3 数据绑定的两种形式及其选择在JS FA中数据绑定主要有两种形式一种是双大括号{{ }}用于文本内容的绑定另一种是直接绑定属性值比如checked{{ isChecked }}这种。对于输入框来说如果你想让输入框的值和某个数据变量双向同步可以用value{{ inputValue }}的方式。但在这个项目里我选择在用户点击按钮的时候再去读取输入框的值而不是实时同步。这样做的好处是逻辑更清晰用户输入过程中不会频繁触发数据更新。提示如果你确实需要实时获取输入框的值来做一些即时校验那就用双向绑定。如果只是等用户输入完再统一处理用事件回调的方式更合适。3.4 样式文件的基本布局思路CSS文件负责让页面看起来舒服一点。核心就是让所有元素垂直居中排列间距适中。容器用flex布局方向设为column这样里面的元素会自动从上到下排列。标题字号大一点提示文字颜色稍微淡一点输入框和按钮给一个合适的宽度和内边距。这些细节不复杂但做好了用户体验会好很多。.container { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100%; padding: 0 40px; } .title { font-size: 28px; font-weight: bold; margin-bottom: 30px; } .hint { font-size: 18px; color: #666666; margin-bottom: 20px; text-align: center; } .guess-input { width: 100%; height: 48px; border: 1px solid #cccccc; border-radius: 8px; padding: 0 12px; margin-bottom: 20px; } .btn-guess { width: 100%; height: 48px; background-color: #007dff; color: #ffffff; border-radius: 8px; margin-bottom: 12px; } .btn-reset { width: 100%; height: 48px; background-color: #f0f0f0; color: #333333; border-radius: 8px; }这套样式不追求好看但保证在大多数设备上都能正常显示、方便点击。等游戏逻辑跑通了你再慢慢调样式也不迟。4. 游戏逻辑的核心状态设计与JS实现4.1 游戏需要记住哪些数据写逻辑之前先想清楚这个游戏在运行过程中需要记住哪些信息正确答案是多少targetNumber当前提示文字是什么hintText游戏是否已经结束isGameOver用户当前输入的值inputValue这四个数据就是整个游戏的状态。其中targetNumber和isGameOver是内部状态不需要直接显示在页面上但逻辑判断要用到。hintText和inputValue是跟页面显示相关的状态。在JS FA中所有需要在页面上使用的数据都必须放在data对象里。只有放在data里的属性值变化时才会触发页面刷新。这一点非常关键我见过有人把变量定义在data外面然后纳闷为什么页面上不更新。4.2 初始化逻辑生成随机数和重置状态游戏开始时需要做几件事生成一个1到100之间的随机整数作为答案把提示文字设为初始提示把游戏结束标志设为false。export default { data: { targetNumber: 0, hintText: 我想了一个1到100之间的数字你猜猜看, isGameOver: false, inputValue: }, onInit() { this.resetGame(); }, resetGame() { this.targetNumber Math.floor(Math.random() * 100) 1; this.hintText 我想了一个1到100之间的数字你猜猜看; this.isGameOver false; this.inputValue ; } }onInit是页面的生命周期函数页面初始化时自动调用。在这里调用resetGame保证每次进入页面都是一个全新的游戏。Math.random()生成一个0到1之间的浮点数乘以100之后变成0到100之间的浮点数用Math.floor向下取整得到0到99的整数再加1就变成了1到100。这个计算过程很经典但每次写的时候都值得确认一下边界值对不对。4.3 处理用户输入与猜测逻辑用户点击确认按钮时需要做以下几件事读取输入框的值判断是否为空、是否为有效数字。把用户输入的数字和正确答案比较。根据比较结果更新提示文字。如果猜对了把游戏结束标志设为true。onInputChange(e) { this.inputValue e.value; }, onGuess() { if (this.isGameOver) { return; } const guess parseInt(this.inputValue); if (isNaN(guess) || guess 1 || guess 100) { this.hintText 请输入1到100之间的有效数字; return; } if (guess this.targetNumber) { this.hintText 恭喜你猜对了答案就是 this.targetNumber; this.isGameOver true; } else if (guess this.targetNumber) { this.hintText 你猜的 guess 太小了再试试大一点的; } else { this.hintText 你猜的 guess 太大了再试试小一点的; } }这里有几个细节值得展开说。第一onInputChange接收一个事件对象e通过e.value拿到输入框当前的值。这个事件在用户每次修改输入内容时触发把值同步到inputValue变量里。这样在点击按钮的时候直接读this.inputValue就行了。第二输入校验不能省。用户可能什么都不输入就点按钮也可能输入一个超出范围的数字。如果不做校验parseInt一个空字符串会得到NaN后续比较就会出问题。所以先判断isNaN和范围不合法就直接给提示并返回。第三猜对之后把isGameOver设为true这样后续再点确认按钮就不会有反应了。这是一种简单的状态保护机制防止游戏结束后还能继续猜。4.4 重置逻辑与状态清理重置按钮的逻辑很简单就是调用resetGame方法。但这里有一个容易忽略的点重置的时候需要把输入框里的内容也清空。因为输入框的值是通过inputValue变量控制的所以把inputValue设为空字符串输入框就会自动清空。onReset() { this.resetGame(); }看起来只是调了一个方法但背后做的事情不少重新生成答案、重置提示文字、清除游戏结束标志、清空输入框。这就是把逻辑封装成方法的好处需要重置的时候调一下就行不用到处复制粘贴。5. 跑通之后才发现的问题调试与优化实录5.1 页面不刷新先检查数据放对位置没有我第一次写的时候把targetNumber定义在了data外面结果游戏逻辑跑起来完全没问题但页面上提示文字死活不更新。排查了半天才发现只有data里的属性变化才会触发UI刷新。定义在外面的变量值变了页面也不知道。这个坑很典型。JS FA的响应式系统是基于data对象做的你不在它管辖范围内的变量它管不着。所以记住一条凡是需要在页面上体现变化的数据一律放进data里。5.2 输入框的值获取不到事件绑定方式要确认另一个坑是输入框的值获取。我一开始用的是onchange事件但发现有些情况下触发不及时。后来查了一下onchange在输入框失去焦点或者按下回车时才触发而oninput是每次输入都触发。如果你需要实时获取输入内容用oninput更合适。如果只是等用户输入完再处理onchange就够了。在这个项目里因为用户输入完之后会点击按钮点击按钮时输入框会失去焦点触发onchange所以用onchange没问题。但如果你做的是实时搜索提示之类的功能就得换成oninput。5.3 数字比较时的类型陷阱parseInt转换之后得到的是数字类型和targetNumber比较时用的是严格相等还是宽松相等结果可能不一样。我建议统一用避免隐式类型转换带来的意外。比如parseInt(5)得到数字5targetNumber也是数字用比较没问题。但如果哪一天你不小心把targetNumber存成了字符串会直接返回false而可能会返回true这种隐式转换在复杂项目里是bug的温床。5.4 游戏体验上的小优化基础功能跑通之后我加了几个小优化体验提升很明显猜对之后把确认按钮置灰或者隐藏防止误操作。可以通过给按钮的enabled属性绑定{{ !isGameOver }}来实现。提示文字里带上用户猜的数字让用户知道自己上一轮猜的是什么。这个在代码里已经体现了。输入框在游戏结束后也禁用避免用户继续输入。同样通过绑定enabled属性控制。这些优化不复杂但能让整个应用看起来更完整、更像个正经的小产品而不是一个半成品Demo。6. 从这个小项目里能带走的通用经验猜数字游戏虽然简单但把JS FA应用开发的几个核心环节都串了一遍。我总结了几条在这个项目里验证过的经验放到其他项目里同样适用。状态设计先行。动手写代码之前先想清楚这个页面需要记住哪些数据哪些数据变化需要反映到UI上。把这些数据列出来放进data里后面的逻辑就是围绕这些数据做增删改查。状态设计清楚了代码怎么写都不会乱。事件绑定要区分场景。onchange和oninput的区别、onclick和ontouch的区别这些看起来是细节但选错了就会导致功能不符合预期。我的习惯是先想清楚这个交互的触发时机是什么再去选对应的事件。输入校验永远不能省。不管是用户输入还是外部数据进到你的逻辑之前都要做校验。空值、非法值、边界值这些情况不处理程序迟早会在某个意想不到的地方崩掉。封装重复逻辑。重置逻辑我封装成了resetGame方法初始化的时候调一次用户点重置按钮的时候再调一次。如果不封装这两处就要写两遍相同的代码改的时候容易漏掉一处。这个习惯在小项目里看不出多大好处但项目一大就是救命稻草。先跑通再优化。我见过不少人一开始就纠结样式好不好看、动画顺不顺畅结果核心功能还没跑通就卡住了。正确的顺序是先让功能跑起来确认逻辑没问题再去调样式和体验。功能是骨架样式是皮肉骨架没搭好皮肉往哪儿贴这个猜数字游戏我后来又改了好几版加了猜测次数统计、加了历史记录显示、加了难度选择。每加一个功能都是在验证上面这些经验。你也可以试试在基础版本跑通之后自己动手加一两个功能那种“我真的学会了”的感觉比看任何教程都来得实在。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询