不知不觉已经是自学小程序开发的第11天了。今天不打算继续往后赶进度,而是回头把前面断断续续接触过的列表渲染、条件渲染、事件绑定和数据处理串起来,做一个完整的待办事项小项目。这个项目不大,但该有的东西全都有:输入框、按钮交互、列表展示、删除操作、状态切换,还有本地缓存。对零基础的人来说,把这几样真正跑通,比囫囵吞枣多看十章教程都管用。
为什么第11天要停下来做整合?因为我前一周多踩过最大的坑,就是每个知识点单独看都懂,一放到真实场景里就不知道从哪下手。比如wx:for会写,但列表里要动态删掉某一项就懵了;bindinput会写,但输入框里的值怎么实时取出来又卡住。这些东西单独拆开都不难,难的是组合在一起的时候怎么让数据在整个页面里流动起来。今天的项目就是把它们全部串一遍,顺便把前端开发里最核心的一个思维——数据驱动视图——彻底搞清楚。
1. 今日学习内容整体设计:为什么要做待办事项,而不是继续追新章节
很多自学前端的朋友容易陷入一个误区:总觉得学得越快越好,今天看完组件明天就想看API,后天恨不得直接上手复杂项目。我自己前几天的状态也差不多,结果就是学完的东西没在脑子里留下多少。今天这个安排,核心思路就是四个字——回头整合。与其学一堆似懂非懂的新概念,不如把手头已有的知识练成肌肉记忆。
1.1 前10天知识回顾与Day11定位
简单梳理一下我前10天走过的路,大家可以对号入座看看自己处在哪个阶段:
- Day1到Day3:环境搭建,装了微信开发者工具和HBuilderX,搞明白了小程序的目录结构,知道
pages、app.json、app.js这些文件是干什么的。 - Day4到Day6:开始写页面,学了
view、text、image、input、button这些基础组件,会调整wxss样式,大概理解了rpx这个单位。 - Day7到Day8:接触了数据绑定和事件,会用
data里定义变量,然后通过{{}}渲染到页面上,也知道了bindtap可以给组件绑定点击事件。 - Day9到Day10:学了一些中级内容,包括
wx:if条件渲染、wx:for列表渲染,还简单了解了一下wx.setStorageSync本地缓存。
到了Day11,基础组件、数据绑定、事件、列表渲染、条件渲染这几个核心能力都已经接触过了。但问题也来了:这些能力是零散的,就像工具箱里摆了一堆螺丝刀和扳手,但还没亲手组装过一件东西。今天这个待办事项项目,就是第一次把这些工具组合起来使用。
1.2 为什么选择做一个待办事项应用,以及它涵盖的知识点
选待办事项这个题材,不是因为它新鲜,而是因为它足够经典,而且每个功能点都能对应到一个前端开发的高频知识点。你仔细拆解一下就会发现,几乎所有小程序或网页应用,底层逻辑都是这一套:
- 有一个输入框,用户往里输内容——对应
input组件的使用和数据获取。 - 有一个添加按钮,点了之后内容出现在下方列表里——对应事件绑定和数组追加数据。
- 列表里的每一项可以标记为已完成——对应条件渲染、样式切换和数据修改。
- 每一项可以删除——对应数组删除操作和视图刷新。
- 整个列表要能存下来,下次打开还在——对应本地缓存。
这个流程走完,你其实就把前端开发最核心的"数据驱动视图"这个概念彻底跑通了。我后面会详细解释什么叫数据驱动视图,但现在你只需要记住一句话:页面长什么样,完全由数据决定。你要改页面,不是直接去改界面,而是改数据,界面会自动跟着变。这个思维一旦建立起来,后面学vue、react这些框架都会轻松很多。
1.3 今日项目的预期目标和前置要求
开始之前先明确一下今天做完你能得到什么。最直观的成果是一个能正常运行的待办事项小程序:输入文字、点按钮、添加条目、点勾标记完成、点删除移除条目、刷新页面数据还在。如果你能独立把这几件事做出来,那说明你的小程序开发基础已经真正打牢了,可以开始往更深的方向走了。
前置要求不多,只要满足两条:一是电脑上装好了微信开发者工具,并且能创建小程序项目;二是大概知道app.json和页面文件的组织方式。如果前两条还不熟悉,建议先花一两个小时把这两个东西搞清楚再来做今天的实践。因为今天的重点不在环境搭建,而在于代码逻辑本身。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 四个核心知识点深度拆解:列表、条件渲染、事件和数据流
待办事项项目虽然不大,但它涉及到的几个知识点,每一个都是小程序开发里使用频率极高的。为了让大家后面做项目的时候不卡壳,我会把这几个知识点一个一个拆开讲清楚,并且特别说明它们为什么是这么设计的。搞懂了背后的道理,比记住几个写法要重要得多。
2.1 wx:for列表渲染:为什么列表一定需要key值
wx:for是小程序里用来循环渲染列表的指令。假设你的data里有一个数组todos,里面存着三件事,你想把它们都显示在页面上,不需要手写三个view标签,只需要写一个view,然后用wx:for让它循环三遍。
最基本的写法是这样:
html复制<view wx:for="{{todos}}" wx:key="id">
{{item.text}}
</view>
这里有几个细节需要解释一下。循环的时候,小程序默认把数组里的每一项命名为item,把每一项的索引命名为index。如果你想自己改名字,可以用wx:for-item指定循环项的变量名,用wx:for-index指定索引的变量名。不过通常情况下,直接用默认的item和index就够了。
然后是wx:key,这个属性非常重要。它的作用是给每一个循环出来的元素一个唯一标识,让小程序能够精准地知道哪个元素是哪个。为什么要这个标识?你想象一下,如果列表里有一百项,你删掉了第三项,如果没有key,小程序只能从头到尾重建这一百项;有了key,它可以精确地只处理变化的那一项。这在数据量小的时候感觉不出来,但数据量大了以后,性能差别非常明显。
而且wx:key还有一个作用,就是保持组件自身的状态。比如列表里的每一项都有一个输入框,用户在第一项里输入了内容。如果没有key,当列表顺序改变的时候,小程序可能分不清哪个输入框对应哪个数据,导致输入的内容错乱。加了唯一的key值,每一个组件就和数据绑定了,怎么排序都不会乱。
我自己在实际写的时候,key值通常就用数据里的id。这个id是每一条数据独有的,不会重复。如果你没有id,可以退而求其次用index,但那样会有潜在问题,因为通过index找数据在删除场景下会出错,所以建议大家从一开始就养成给数据加id的习惯。
2.2 wx:if与hidden:什么时候用条件渲染,什么时候用隐藏切换
待办事项里有一个很常见的需求:当列表为空的时候,显示一个"暂无待办事项"的提示;当列表里有内容的时候,显示列表本身。这种"根据条件决定显示什么"的写法,就是条件渲染。
wx:if的用法很直观:
html复制<view wx:if="{{todos.length === 0}}">
暂无待办事项,快添加一条吧
</view>
<view wx:else>
<!-- 列表内容 -->
</view>
当todos数组为空的时候,第一段显示;有内容的时候,显示wx:else后面的部分。这个逻辑在写业务代码的时候用得特别多。
还有一个容易混淆的指令叫hidden,它也可以控制元素的显示和隐藏:
html复制<view hidden="{{isHidden}}">
这一段可以通过hidden隐藏
</view>
那wx:if和hidden到底有什么区别?简单来说,wx:if是"惰性"的,当条件不满足的时候,它压根不会渲染这个组件,一个元素都不生成;hidden是"不管怎样都渲染",只是通过样式把元素藏起来,不让你看到。
这个区别带来了一个非常实际的选择标准:如果元素需要频繁地在显示和隐藏之间切换,比如用户在勾选和取消勾选待办事项的状态图标,那就用hidden,因为它只是切换样式,不需要重新创建和销毁组件,性能更好。如果元素几乎不会变化,比如空列表的提示文字,那就用wx:if,因为它可以避免无意义的渲染开销。
我在Day11之前的实际项目里踩过一个坑:用wx:if控制一个高频切换的元素,结果在快速操作的时候页面明显卡顿。后来换成hidden就好了。这就是为什么理解原理比单纯记住写法更重要。
