初学某种编程语言时,很多人会从手撸一个TodoList(待办清单)开始。 咱们也不能免俗,从本章开始,先撸个单机版TodoList,再逐步拓展为Web版本。准备工作 我们在创建小程序项目时,开发工具好心送了些示例代码。 它是一个获取用户登录数据的小Demo。如果你的新版开发工具没有给示例代码,那则无视之。 因此首先将app。wxss和pagesindexindex。wxss中的代码清空,免得它们捣乱。它们分别是全局和页面的样式文件,控制着页面元素的外观。 接下来修改app。json文件:app。json{。。。修改字段window:{。。。navigationBarBackgroundColor:6495ED,navigationBarTitleText:TodoList,。。。},。。。新增字段useExtendedLib:{weui:true}} app。json是全局配置文件,控制着项目的基本属性。 window字段指定了小程序的字体颜色、导航栏样式等等属性。这里我们将导航栏的背景修改为淡蓝色,将页面标题修改为TodoList。保存文件后,开发工具左侧的手机模拟器会自动更新,可以发现导航栏已经变为蓝色了。 useExtendedLib指定了本项目要使用扩展库WeUI。WeUI是官方提供的一套UI样式库,用过Bootstrap的朋友上手起来会比较快。原生的UI实在有点难用(且丑)。类似WeUI的样式库还有很多,这个就读者以后去探索了。 扩展库的概念类似于Python开发时用pip安装第三方库,不同的是扩展库并没有将三方库安装到程序包中,而是对公共资源的某种引用。因此使用扩展库的好处是它不占小程序自己的体积,但是缺点是目前支持的库非常的少,WeUI就是其中之一。 小程序的体积应当尽可能小。体积小的好处是首次启动时加载时间较短,用户体验佳。另一方面是因为微信规定小程序有体积上限,超过上限是无法部署到线上的。见小程序最大体积。 准备工作这样就完成了,接下来开始撸正经代码。WXML模板 从事过网页编程的人知道,网页编程采用的是HTMLCSSJS这样的组合,其中HTML描述页面的结构,CSS描述页面的样子,JS处理页面和用户的交互。 在小程序中也有同样的角色,其中WXML充当的就是HTML的角色。 根据app。json中的配置可知,pagesindex是小程序的首页。因此首先清空pagesindexindex。wxml的内容,然后写入下面的神秘文字:!pagesindexindex。wxmlviewclasscontainerviewclassweuicellsweuicellsaftertitlecheckboxgroupbind:changecheckboxChangelabelclassweuicellweuichecklabelwx:for{{items}}wx:keyidviewclassweuicellhdcheckboxvalue{{item。id}}checked{{item。checked}}viewviewclassweuicellbd{{item。content}}viewlabelcheckboxgroupviewview是小程序中的最基础的视图容器,类似HTML的标签p。此外小程序还提供了button,text等等标签,以及地图、视频、音频、扫码等等开放能力。与传统网页开发不同,小程序的模板可以包含if、for等逻辑控制语法。比如上面的wx:for{{items}}语句,意思是循环渲染items容器中的元素(items后面马上会定义)。{{}}花括号表示这里不是一个普通的字符串,而是实实在在的数据。wx:key用于帮助模板引擎识别每个items元素,类似于数据库中的主键。是多选框控件整体。bind:changecheckboxChange意思是监听多选框控件的状态,每当其内容发生变化时,立即调用checkboxChange()方法(此方法后面马上会定义)。bind:change是监听控件事件的内置固定写法,类似的还有按钮的bind:tap、输入框的bind:input等等。为多选框的实际单个元素。value为其绑定的数据,checked属性表示它是否被选中。 除此之外,代码里还有很多类似weuicellsweuicellbd之类的属性,这个就是WeUI提供的美化UI控件外观的样式了,有需要对照WeUI文档抄过来即可,和Bootstrap差不多,就不展开讲了。读者可以尝试把这些属性删除后,看看多选框外观的变化。JS逻辑层 上面的WXML中出现了两个非常关键的东西:items,它是数组类型的数据,提供多选框循环渲染所需的内容。checkboxChange()方法,它的作用是监听多选框的状态,一但发生变化则执行某些逻辑处理。 在传统的网页开发中,接下来就应该在页面底部写Javascript脚本,定义这些数据和方法了。但小程序强大的地方在于:它将视觉外观的渲染,和逻辑层彻底拆开了,各司其职。 来实际体验下。清空pagesindexindex。js中的示例代码,写入下面这一坨:pagesindexindex。jsPage({页面持有的状态数据data:{items:〔{id:3,content:和丢丢去超市买白菜,checked:false,},{id:2,content:周二和老王吃烧烤,checked:false,},{id:1,content:凌晨给老板汇报工作,checked:false,}〕,},监听多选框的状态改变事件checkboxChange(e){页面持有的数据获取本地数据的写法为this。data。xxxconstitemsJSON。parse(JSON。stringify(this。data。items))checkbox持有的数据constvaluese。detail。value将items和values进行对比根据values的值更新页面数据(即data。items)for(leti0,lenIitems。ilenI;i){items〔i〕。checkedfalsefor(letj0,lenJvalues。jlenJ;j){values〔j〕是String将其转换为Intif(items〔i〕。idparseInt(values〔j〕)){items〔i〕。checkedtruebreak}}}更新数据this。setData({items:items})打印的内容会展现在调试器中console。log(this。data。items)},}) 分解上面的内容:小程序的每个页面,都需要在对应的js文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。所以你可以看到,这个js文件中所有代码都是在页面构造器Page()中的。data字典对象,它持有了当前页面所有的本地状态。大多数情况下,你都应该将数据放到这里集中管理。一但其中的数据发生变化,小程序能够感知到并且立即自动更新页面中对应的元素。这种模式简化了程序员智力负担,你不再需要手动更新页面使其和数据相对应。这也就是传说中的数据绑定,或者叫数据驱动了。 页面中所有需要用到的方法也都定义在Page()构造器中,比如checkboxChange()。几个值得关注的地方:它的参数e是多选框控件传递进来的,包含整个控件的状态和数据。你可以用console。log(e)打印看看里面的内容。方法用了两个for循环检查了多选框的状态,如果当前条目被选中则将items中对应的条目设置为已选中(。checkedtrue),如果未被选中则设置为。checkedfalse。调用Page构造器内置的方法this。setData({。。。})更新数据,以键值对的方式给出。注意页面持有的状态必须用this。setData(),不能手动更新(比如用等号赋值),否则将导致渲染不同步等bug。赋值局部变量时用JSON。parse(JSON。stringify(。。。))实现了深拷贝。如果这里直接用等号赋值constitemsthis。data。items,仅仅是传递了对数据的引用(浅拷贝),在后续操作中将违背不能手动更新本地状态的原则。 这就大功告成了。 注意到没有,逻辑层只关注了data中数据的状态。至于更新渲染的工作,框架自动帮你完成了。 保存文件,重载模拟器效果如下: 神奇吧。强烈建议第一次接触数据驱动模式的读者在这里停一下,对比观察wxml和js文件中各个控件、事件、数据、方法之间的对应关系。Component构造器 上面用的Page构造器适用于简单的页面,对于复杂的页面它可能并不好用。 幸好小程序还提供另一种选择:Component构造器。虽说Page和Component有很多细节上的差别,但就目前这个简单的例子来说,唯一的区别是:方法需要放在methods:{}里面。 试试改造它:pagesindexindex。jsComponent({data:{items:〔。。。〕},methods:{checkboxChange(e){。。。}},}) 功能完全一致。 后续章节将以Compnent构造器为主讲解,想了解它两更多区别和细节的可参考文档。总结 现在我们有个可以瞎点来点去的多选框列表了。但这没用啊,它只是个固定内容的小玩意。 下一章继续探讨小程序的数据输入,让示例真正动起来。 点赞or吐槽?来博客或GitHub评论区!