第一周接触微信小程序开发,最常见的状态是:资料收藏了一堆,视频看了三集,代码一行没写。我自己带新人时就发现,week1 这个阶段最不该贪多,因为小程序虽然看起来只是网页开发的变体,但它的环境、目录结构和调试方式都有一整套自己的逻辑。只要第一周把工具链跑通、把一个最小页面做出来,后面学组件和 API 会快得多。
这篇文章按“微信小程序开发week1”的实际进度来写,没打算让你一周变全栈,而是给出一份可以照做的路线:先定目标,再搭环境,再解剖项目结构,最后用一个记账本首页把渲染和交互串起来。如果你是零基础,请把它当周计划用;如果你已经能写一点代码,可以直接跳到第4、5节看实操。
1. 第一周的目标拆解:别把七个晚上浪费在“准备”上
第一周最容易踩的坑,是花了四天看教程、装软件、查资料,结果到周末连一个能点的小程序页面都没跑起来。微信小程序开发的第一周,核心目标不是“学会所有组件”,而是“建立起一套最小可运行的心智模型”:知道文件怎么组织,知道页面怎么渲染,知道点击事件怎么触发。
1.1 第一周最该完成的任务清单
我建议你按下面的清单来分配时间,而不是按照官方文档的顺序从头读到尾:
| 时间段 | 任务 | 完成标准 |
|---|---|---|
| 第1晚 | 安装微信开发者工具,新建项目 | 能在模拟器里看到默认页面 |
| 第2晚 | 拆解默认项目结构 | 能说清楚 app.json、app.js、pages 目录的关系 |
| 第3晚 | 写一个简单的“自我介绍”页面 | 会用 view、text、button 和基本样式 |
| 第4晚 | 学习数据绑定和事件绑定 | 点击按钮后页面文字变化 |
| 第5-6晚 | 做记账本首页 | 页面分类切换、列表展示、本地缓存 |
| 第7晚 | 真机预览,修复基础问题 | 在手机上看到并操作自己的页面 |
这张表不是我拍脑袋定的,而是从多次带新人的经验里总结出来的节奏。很多人第一周失败不是因为不努力,而是因为目标太抽象,比如“学会小程序开发”,这种目标没法验收。换成“点击按钮文字变化”之后,每晚会有一个明确的完成信号,心态会稳很多。
1.2 为什么要从单页面功能做起
小程序虽然支持 tabBar、分包、云开发这些高级能力,但第一周完全用不上。我见过不少新手一上来就想复刻一个完整电商应用,结果被导航、支付、登录流程劝退。正确做法是选一个极小的场景,比如“记账本首页”或者“个人信息页”,把页面渲染、用户交互、临时数据保存这三件事跑通。
单页面功能最大的价值,是让你把注意力集中在基础模型上:WXML 负责结构,WXSS 负责样式,JS 负责逻辑和数据,setData 负责把数据从逻辑层送到视图层。这四个角色只要在一页里搞明白,几乎所有小程序页面都适用。反过来,如果第一周就追着复杂架构跑,你很难判断问题是出在语法上,还是出在设计上。
1.3 适合谁参考这条路线
这条路线适合三类人:完全没写过小程序的零基础新手;会一点 HTML/CSS,但不太理解小程序数据流的网页开发者;以及需要在一周内快速交付一个演示项目的在校学生或个人开发者。
如果你已经有比较扎实的前端基础,比如熟悉 Vue 或 React 的响应式更新,学小程序会更快,因为核心思路类似,只是换了一套 API。哪怕你完全没写过代码,只要愿意每天留出两到三小时,按上面的清单执行,第一周也能做出一个看得见、摸得着的小程序页面。别被“编程很难”吓住,小程序的语法比传统 Web 开发更克制,反而容易上手。
2. 环境搭建:开发工具与项目配置避坑指南
工具链是第一个劝退点。很多新手下载了开发者工具,新建项目时却卡在 AppID 和模板选择上。这一节我会把环境搭建过程中的关键选择讲清楚,并补充一些平时文档里不会专门提到的细节。
2.1 开发者工具安装与第一眼配置
微信开发者工具是默认的 IDE,直接去官网下载稳定版即可。安装过程没有特殊技巧,但要注意:首次打开时登录需要扫码,这个二维码是用微信扫码,不是小程序码。很多人在这一步会扫错,耽误不少时间。
进入工具后,建议先打开“设置”里的“编辑器设置”,把“热重载”和“自动保存”打开。热重载是我比较依赖的功能,它能在你保存 WXML 或 JS 文件时自动刷新模拟器,省掉手动点编译的重复操作。另外,界面右侧的“调试器”面板会显示 Console、Network、AppData 等子面板,第一周至少要养成看 Console 和 AppData 的习惯:前者报错,后者查看当前页面数据。
2.2 AppID:测试号还是正式注册
新建项目时会让你填 AppID,旁边有一个“测试号”选项。我的建议是:如果只想在模拟器里练手,选测试号完全够用;但如果希望真机预览、调用登录接口、发布上线,就必须去公众平台注册一个小程序账号,拿到正式的 AppID。
我刚学的时候用了两天测试号,后来发现没 AppID 无法在手机上预览,才意识到这个区别。要注意的是,一个微信号能注册的小程序数量有限,如果你只是学习,没必要急着注册多个。开发工具里的测试号本质上是临时身份,默认项目里也会带一个“云开发”入口,第一周可以忽略它,避免思路被打散。
2.3 新建项目时模板怎么选
开发者工具提供 JavaScript、TypeScript、云开发等不同模板。对第一周的初学者,选“JavaScript 基础模板”就对了。TypeScript 虽然有类型提示,但多一层编译配置,对零基础来说会增加干扰;云开发模板又引入了云函数和数据库,概念负担太重。
新建项目后,你会看到一个默认的 demo 项目,通常包含 logs 页面和几个示例文件。我的建议是直接删掉示例代码,自己从零建一个页面。因为看十遍示例不如自己敲一遍,删掉重写能让记忆深刻很多。如果不知道怎么删,找到 pages/index/index.wxml 文件,把内容清空改成你自己的结构即可。
2.4 真机预览前的三个检查项
第一周最后一定会遇到真机预览,这里有三个检查项要提前确认。第一,开发者工具和手机微信必须是同一账号体系,扫码的人要和登录开发者工具的微信号一致。第二,项目必须绑定了正式 AppID,测试号不支持真机预览。第三,预览时如果页面请求了本地接口,需要在开发者工具右上角“详情”->“本地设置”里勾选“不校验合法域名...”,否则手机上的请求会被拦截。
最后一个坑非常典型:模拟器里接口跑得好好的,一到真机就报 “url not in domain list”。这不是代码问题,而是小程序的域名白名单机制。第一周如果只是学习,可以在开发者工具的本地设置里关掉校验,但心里要有数:将来上线前,必须把接口域名加入后台白名单,并且要求 HTTPS。
3. 项目结构解剖:搞懂文件分工再开始写代码
很多人第一周最困惑的就是“为什么一个页面有四五个文件”。小程序不是传统意义上的单 HTML 页面,它把结构、样式、逻辑、配置全部拆开了。这一节我会把根目录和页面目录的角色讲清楚,并且补充执行顺序。
3.1 根目录下的四个文件各自做什么
新建一个基础项目后,根目录至少有四个文件:app.js、app.json、app.wxss、project.config.json。我习惯把它们理解成一套“团队分工”:
- app.js 是整个小程序的生命周期入口,负责全局逻辑和全局数据。
- app.json 是全局配置,包括页面路径、窗口样式、tabBar 等。
- app.wxss 是全局样式,所有页面都会继承这里的公共样式。
- project.config.json 是开发者工具的项目配置,相当于编辑器的“记忆”,一般不需要手改。
这四个文件里,最容易被忽略的是 app.json。它里面有一个pages数组,数组的第一项就是小程序的首页。很多新手改完页面路径后报错,就是因为没有在 app.json 里注册新页面。这是小程序和 Web 开发最大的差异:Web 里一张 HTML 能被直接访问,小程序里的每个页面必须先登记,否则编译时直接报“页面找不到”。
3.2 页面目录里的“小四件”
每个页面目录下通常也有四个文件,比如 pages/index/ 里有 index.wxml、index.wxss、index.js、index.json。我把它们称为“页面小四件”。其中 WXML 决定页面上有什么,WXSS 决定长什么样,JS 决定数据和交互,页面的 JSON 则负责覆盖局部的窗口配置,比如自定义导航栏标题。
这里有一个很容易误解的点:页面不一定要四个文件齐备。如果页面没有独立样式,可以不放 WXSS;如果不需要覆盖全局配置,也可以不放 JSON。但为了规范,第一周我还是建议四个文件都建好,因为后续你不确定哪些能力会用到,保持完整结构可以减少思考成本。页面文件在编译时会被打包,命名建议使用小写英文和数字,不要用中文或特殊字符。
3.3 JSON 配置里的注册逻辑
小程序的页面注册逻辑并不复杂,但极其重要。以 app.json 为例:
{ "pages": [ "pages/index/index", "pages/list/list" ], "window": { "navigationBarTitleText": "我的小程序" } }pages数组里写的是页面路径,不需要写.wxml后缀。这里的顺序会影响编译结果,排在第一位的就是启动页。如果列表页想作为首页,把它移到第一位即可。开发者工具中的“编译模式”可以临时指定启动页面,但那只是调试时起效,不会改变真实线上首页。
很多新手会遇到一个现象:新建了页面目录,也在 app.json 里加了路径,但模拟器里依然白屏。大概率是路径写错了,比如少了pages/前缀,或者文件名和目录名不一致。检查这类问题最快的方式,是看开发者工具 Console 里的报错信息,它通常会直接给出“未找到 app.json 中的页面”字样。
3.4 执行顺序:从 App 到 Page
理解执行顺序,是后面学生命周期的基础。启动小程序时,微信会先加载 app.js,执行App()函数注册小程序实例;然后根据 app.json 里的页面路径,加载对应的页面 JS,执行Page()函数注册页面实例。页面的 JS 在执行时,会按照生命周期依次触发onLoad、onShow、onReady等方法。
我在第一周教新人的时候,常用一句话概括:全局先跑,页面后跑;注册先做,渲染后做。也就是说,你在 app.js 的globalData里定义的数据,页面 JS 中可以访问,但必须等页面初始化完成后再去读,否则容易拿到 undefined。很多看起来像是“数据丢了”的 bug,八成是执行顺序没理清。
4. 渲染与交互:第一周必须拿下的五个知识点
模板和样式不是小程序学习的重头戏,数据绑定、生命周期、事件绑定、条件渲染和列表渲染才是。这一节我会挑第一周最常用的知识点展开,每个都附带我实际写代码时的习惯和注意事项。
4.1 数据绑定:{{ }}只是第一步,setData才决定刷新
小程序页面 UI 是数据驱动的,WXML 里用双花括号绑定 JS 数据。你可以在页面 JS 的data字段里定义初始值,然后在 WXML 里用{{ message }}显示它:
<view>{{ message }}</view>Page({ data: { message: 'Hello' } })但这只是“绑定”,真正影响开发效率的是setData。当用户点击按钮、输入内容或者请求接口返回数据后,你需要把新数据告诉页面,必须通过this.setData({ message: 'New Message' })来更新。直接写this.data.message = 'New Message'虽然会改变逻辑层数据,页面却不会刷新,这是新手最常见的困惑之一。
我建议第一周就养成一个习惯:所有需要显示在页面上的动态数据,统一先放进data,再通过setData修改。不要贪图方便在“事件函数里拼接字符串直接操作 DOM”,小程序没有原生 DOM 操作概念,所有 view 的更新都依赖数据状态。
4.2 生命周期:onLoad、onShow、onReady 怎么分工
页面生命周期方法很多,第一周只需要掌握三个。onLoad在页面首次加载时执行,适合做初始化请求;onShow在页面每次从后台切回或从其他页面返回时执行,适合刷新数据;onReady在页面初次渲染完成后执行,这时可以安全地操作组件实例。
用记账本举例子:进入页面时,要在onLoad里读取本地缓存,把历史记录显示出来。如果用户从编辑页返回首页,首页的onLoad不会重新触发,但onShow会触发。所以“从编辑页返回后刷新列表”的逻辑就要写在onShow里。第一周不理解细微差别没关系,先记住一条:和页面“首次出现”相关用onLoad,和“再次出现”相关用onShow。
4.3 事件绑定:bindtap 与 dataset 传参
在 WXML 中,点击事件一般写作bindtap="handleTap"。事件函数定义在页面 JS 的 methods 区域里(Page 配置对象下)。事件对象event里包含很多信息,但第一周最需要关注的是currentTarget.dataset。
<view>handleTap(event) { const id = event.currentTarget.dataset.id console.log(id) }这个><view wx:for="{{records}}" wx:key="id"> {{item.name}} - {{item.amount}}元 </view>
这里有一个必须早期注意的点:wx:key要填一个数组内唯一的值,比如记录的主键id。如果不写,小程序会警告;如果项目里数据没有唯一字段,可以用*this,但性能上不如具体的 key。列表频繁更新时,key 能帮助小程序精准定位需要更新的节点,避免整个列表重新渲染。
条件渲染wx:if用于控制元素是否渲染,比如“没有记录时显示空状态”。它和hidden属性有区别:wx:if是惰性的,条件不满足时根本不渲染;hidden只是通过样式隐藏。如果切换频率高,hidden可能更轻量;如果初始条件很少为真,wx:if更合适。第一周不用深究性能,先把两种写法和适用场景记住。
4.5 写样式必懂的单位:rpx 与 flex
小程序最常用的长度单位是rpx,全称 responsive pixel,它把屏幕宽度固定为 750rpx。比如设计稿是 375 宽,写一个宽度占屏幕一半的元素,直接用width: 375rpx就行,不用关心设备屏幕到底多少像素。这个设计让开发者从媒体查询里解放出来,但要注意在文字大小、边框等细节里,rpx在不同设备下的表现可能会和设计稿有细微出入,第一周先按“设计稿 1px = 2rpx”来换算即可。
布局方面,我推荐第一周牢牢掌握 flex。小程序的页面结构大多是纵向排列和横向均匀分布,flex 足够处理 90% 的日常需求。比如记账本首页的分类栏,用一个display: flex和flex: 1就可以让多个分类平分宽度,比手工计算百分比简单得多。遇到布局乱掉时,优先检查父容器是否设置了display: flex,子元素是否设置了flex: 1和必要的gap或margin。
5. 第一周实战案例:每天记账首页从零到一
这部分我用一个“每日记账”首页作为实战目标,带你完整走一遍需求拆解、结构编写、交互实现和数据持久化。这个案例足够小,但不至于太玩具,做完之后你会对小程序开发流程有一个整体感觉。
5.1 先拆需求,别急着打开代码编辑器
很多新手拿到需求后的第一反应是“开始写代码”,其实正确顺序是先拆组件。记账首页第一周只做三块:顶部显示本月支出总额;中间是分类标签,比如餐饮、交通、购物;下方是消费记录列表,每条记录包含名称、金额和时间。
分类为什么要做成标签,而不是静态文字?因为它要可点击,点击后列表要筛选出对应分类的记录。这就是“数据驱动交互”的最小模型。列表数据从哪里来?第一周不接后端,使用本地缓存wx.setStorageSync即可,这样既能实现数据保存,又不会陷入接口联调的泥潭。整个场景可以这样理解:一个纯前端、单页面、有状态、有存储的小程序。
5.2 页面结构:view、text、scroll-view 组合
首页结构用 WXML 写出来并不复杂,核心是层级清晰:
<view class="page"> <view class="header"> <text class="total">本月支出</text> <text class="amount">{{totalAmount}}元</text> </view> <view class="category-bar"> <view class="category-item {{currentCategory === item ? 'active' : ''}}" wx:for="{{categories}}" wx:key="*this" >data: { categories: ['全部', '餐饮', '交通', '购物'], currentCategory: '全部', records: [], showRecords: [] }, onCategoryTap(event) { const category = event.currentTarget.dataset.category const records = this.data.records const showRecords = category === '全部' ? records : records.filter(item => item.category === category) this.setData({ currentCategory: category, showRecords: showRecords }) }这里有一个容易被忽略的细节:category === '全部'的判断用的是字符串,而>saveData() { wx.setStorageSync('records', this.data.records) }
读取数据时:
onLoad() { const records = wx.getStorageSync('records') || [] this.setData({ records: records, showRecords: records }) }本地缓存的坑主要有两个:一是数据格式,如果读取到的是undefined,必须用|| []兜底,否则wx:for会直接报错;二是缓存没有过期机制,不适合放敏感数据,只适合放用户偏好或临时草稿。这里我还想多说一句:同步 API 会在写入时阻塞 JS 线程,日常开发量小没问题,但如果你发现页面滑动有卡顿,可以换成异步版本wx.setStorage,第一周先不用过度优化。
6. 常见问题与排查技巧实录
这一节把我在第一周带新人时见过频率最高的问题整理成速查表,每个问题都附上排查思路。真遇到了不用慌,先按顺序查,大多数都是小配置问题。
6.1 页面白屏,控制台却没有报错
白屏但没报错,最可能的原因是 WXML 结构里使用了无法渲染的内容,或者页面的容器高度为零。常见原因是父级view没有设置高度,子元素样式又用了height: 100%,但父级本身没有高度,最终页面一片空白。
另一个常见原因是数据格式不对。比如wx:for遍历的是一个对象而不是数组,控制台不会直接报错,但页面渲染不出来。排查技巧是打开调试器的 AppData 面板,看list或records字段到底是不是数组。如果数据结构没问题,就检查样式的flex布局是否把内容挤出了可视区,可以临时给根节点加一个背景色,直观看到边界在哪里。
6.2 调用了 setData,页面却没有任何变化
setData 没有触发刷新,常见原因有三个:第一个是调用this.setData时,this 的指向已经变了,比如在wx.request的回调里用了普通 function 而不是箭头函数,导致this指向不再指向页面实例;第二个是 setData 的数据路径写错,比如setData({ 'records[0].amount': 10 })括号写法不当时无法生效;第三个是前后的数据引用相同,比如你直接修改数组的一个对象属性后,又把整个数组 setData 回原数组,小程序可能对比不到变化。
针对第二个问题,可以在 setData 之前先console.log打印一份新数据,确认对象结构和你预期一致。针对第三个问题,最佳实践是不直接修改复杂对象,而是用扩展运算符创建一个新数组:const newRecords = [...this.data.records],修改后再 setData。习惯这种做法以后,很多诡异的不刷新问题都会消失。
6.3 本地开发时请求接口总是失败
第一周很多时候会用wx.request请求本地后端,比如http://127.0.0.1:3000。在开发者工具里能通,是因为本地设置关闭了域名校验;但真机预览时微信不允许访问http://localhost和127.0.0.1,因为手机上不存在“本机”这个地址。真机要访问你电脑上的本地服务,必须把接口地址改成电脑在局域网里的 IP,例如http://192.168.1.100:3000,并且手机和电脑连同一个 Wi-Fi。
还有一种情况是请求通到了,但 CORS 报错。小程序客户端不存在跨域问题,但如果你在本地后端写了严格跨域限制,个别开发环境会拦截。第一周图省事的话,可以在后端响应头里加Access-Control-Allow-Origin: *,或者干脆先不做真实请求,用本地缓存模拟数据。
6.4 模拟器正常,真机上布局却乱掉
模拟器里的屏幕比例和真机不一定相同,尤其是刘海屏、挖孔屏等异形屏。第一周最常见的现象是:顶部内容被状态栏遮挡,或者底部按钮被 home indicator 遮挡。解决顶部遮挡,可以在页面 JSON 里配置"navigationStyle": "custom",然后自己用wx.getWindowInfo()获取状态栏高度,给头部留出 padding。解决底部遮挡,可以使用env(safe-area-inset-bottom)增加安全区 padding。
另外,某些真机的微信基础库版本可能比开发者工具低,导致新特性不生效。建议先在“详情”面板里把调试基础库调成和你手机版本一致,再预览。第一周不用为兼容所有机型花太多时间,但至少要确保你的主力测试机看起来正常。
6.5 编译模式导致的“页面不对”问题
开发者工具支持自定义编译模式,可以指定某个页面作为启动页。但很多人修改了 app.json 里的pages顺序之后,发现打开工具还是老页面,原因就是“编译模式”里固定了启动页面。此时点击工具栏的编译模式下拉框,选择“普通编译”或者“重新编译”即可。
这个坑特别容易和新手混淆,因为它没有任何报错,只是页面不对。如果你在调试时也遇到“明明改了首页却没生效”,大概率就是这个原因。我的建议是第一周尽量少用自定义编译模式,保持默认的“普通编译”,这样每次改动 app.json 后看到的就一定是真实启动流程。
6.6 第一周最值得养成的调试习惯
最后分享一个我在第一周收获最大的习惯:每次写代码前,先在 Console 里打印关键数据。很多人觉得打印日志没有必要,觉得“代码不复杂我能看懂”,但恰恰是小程序的异步回调很多,数据到达的时机很难凭脑子判断。比如在 onShow 里读取缓存时,打印一次数组长度,能立刻看出数据是否真的更新了,而不是靠肉眼盯着页面硬猜。
另一个习惯是“小步提交”。每次完成一个小功能,就用开发者工具里的版本管理提交一次,或者至少复制一份项目备份。第一周改代码常常越改越乱,如果有一个随时能回退的版本,心态会稳很多。这个小习惯看似不起眼,但能帮你把学习过程中的挫败感降到最低。