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