- 这一课学什么
- 准备
- 第一步:一件商品的数据
- 第二步:发布——先检查,再上传图片
- 第三步:一个「已获得值时」,三种用途
- 第四步:搜索和显示
- 第五步:详情页——同一屏切换卡片
- 跑起来看看
- 常见问题
- 动手改一改
- 学完以后
- 用到的组件
- 验证范围
第 5 课 带图商品墙:班级闲置物品交换。发布带图片的物品,大家在商品墙上搜索、看详情,卖家可以下架自己的商品。
这一课学什么
这一课没有新组件,重点是把前四课串起来,做成一个像样的 App:
| 功能 | 用的是哪一课的做法 |
|---|---|
| 服务地址、断网提示 | 第 1 课 |
| 商品列表存成一个列表、先读后写 | 第 2 课 |
| 每件商品是一个字典,按编号找到要删的那件 | 第 3 课 |
| 先传图片拿地址,列表里显示网络图片 | 第 4 课 |
| 新:一个变量记住「这次读取是为了发布还是删除」 | 本课 |
| 新:用显示/隐藏卡片在列表和详情之间切换 | 本课 |


图为由最终 .aia 执行真实积木、连真实服务端生成的布局预览(左:往下滑到商品墙;右:点开别人发布的自行车,没有「下架」按钮),不是真机截图。
准备
服务端照常运行。下载 ShopWall.aia 导入,填服务地址和自己的昵称。
第一步:一件商品的数据
{"id": "1800000300000-512", "name": "二手自行车", "price": "180",
"desc": "骑了一年,刹车新换的", "img": "http://…/files/xxxx.jpg",
"seller": "小红", "time": "01-15 16:05"}
标签 goods 里存的就是这样的字典组成的列表。id 由「当前毫秒数 + 随机三位数」拼成,下架时靠它准确找到是哪一件——不能靠名称,两个人可能都卖「台灯」。
第二步:发布——先检查,再上传图片
global 选中图片 = ""
global 正在请求 = false
when 按钮_发布.Click() {
var 昵称 = trim(文本输入框_昵称.Text)
var 名称 = trim(文本输入框_名称.Text)
var 价格 = trim(文本输入框_价格.Text)
if 昵称 == "" {
底部提示条1.Show("先填昵称,买家才知道找谁")
} else if 名称 == "" or textLength(名称) > 20 {
底部提示条1.Show("物品名称 1~20 个字")
} else if not isnumber(价格) {
底部提示条1.Show("价格要填数字")
} else if 价格 < 0 or 价格 > 99999 {
底部提示条1.Show("价格在 0~99999 元之间")
} else if 选中图片 == "" {
底部提示条1.Show("先选一张物品图片")
} else if 正在请求 {
底部提示条1.Show("正在和服务器通信,稍等一下")
} else {
var 小图 = 图片处理1.Compress(选中图片, 1280, 80)
if 小图 == "" {
底部提示条1.Show("这张图片处理不了,换一张试试")
} else {
微数据库1.StoreValue("nickname", 昵称)
按钮_发布.Enabled = false
标签_发布状态.Text = "正在上传图片……"
Web客户端1.Url = join(微数据库1.GetValue("serviceUrl", ""), "/upload")
Web客户端1.PostFile(小图)
}
}
}
先检查再上传:所有输入都合格才开始传图片,免得图片传上去了才发现名称没填。
上传成功后(「获得文本时」),把商品字典放进 待发布,设 动作 = "发布",再去取 goods 列表——和第 4 课一样,代码见 .aia。
第三步:一个「已获得值时」,三种用途
刷新、发布、下架都要先读 goods,结果都回到同一个事件。用全局变量 动作 记住这次读取是为了什么:
global 动作 = ""
global 待发布 = ""
global 待删除 = ""
global 全部 = []
when 网络微数据库1.GotValue(tagFromWebDB, valueFromWebDB) {
var 列表 = choose(islist(valueFromWebDB), valueFromWebDB, [])
if 动作 == "发布" {
listAdd(列表, 待发布)
网络微数据库1.StoreValue("goods", 列表)
} else if 动作 == "删除" {
var 位置 = 0
for i = 1 to length(列表) {
if dictget(select(列表, i), "id", "") == 待删除 {
位置 = i
}
}
if 位置 == 0 {
动作 = ""
底部提示条1.Show("这件已经不在了")
} else {
listRemove(列表, 位置)
网络微数据库1.StoreValue("goods", 列表)
}
}
全部 = 列表
}
- 下架也是先读后写:在最新的列表里按
id找位置再删,不会误删别人刚发布的商品。 - 找不到(别的手机上已经下架了)就提示「这件已经不在了」,什么都不写。
- 「值存储完毕时」同样看
动作:发布成功清空表单,下架成功回到商品墙,最后把动作清空。
第四步:搜索和显示
global 全部 = []
global 显示列表 = []
procedure 显示() {
var 关键字 = trim(文本输入框_搜索.Text)
显示列表 = []
var 项 = []
for i = length(全部) to 1 step -1 {
var 件 = select(全部, i)
if 关键字 == "" or textContains(dictget(件, "name", ""), 关键字) {
listAdd(显示列表, 件)
listAdd(项, 列表显示框_商品.CreateElement(join(dictget(件, "name", ""), " ¥", dictget(件, "price", "")), join(dictget(件, "seller", ""), " · ", dictget(件, "time", "")), dictget(件, "img", "")))
}
}
列表显示框_商品.Elements = 项
}
when 按钮_搜索.Click() {
显示()
}
网络微数据库不能按条件查询,所以搜索是全部取回来在手机上筛。几百件以内很快;商品多到上千件,就该换成能在服务器上查询的数据库了(见专题首页「学完以后」)。
第五步:详情页——同一屏切换卡片
global 当前 = ""
global 显示列表 = []
when 列表显示框_商品.AfterPicking() {
当前 = select(显示列表, 列表显示框_商品.SelectionIndex)
图像_详情.Picture = dictget(当前, "img", "")
标签_详情名称.Text = dictget(当前, "name", "")
标签_详情价格.Text = join("¥ ", dictget(当前, "price", ""))
按钮_下架.Visible = dictget(当前, "seller", "") == trim(文本输入框_昵称.Text)
显示详情(true)
}
procedure 显示详情(显示) {
垂直布局_详情.Visible = 显示
垂直布局_地址.Visible = not 显示
垂直布局_发布.Visible = not 显示
垂直布局_商品.Visible = not 显示
}
when 按钮_下架.Click() {
对话框1.ShowChooseDialog(join("确定下架「", dictget(当前, "name", ""), "」吗?下架后大家就看不到了。"), "下架", "下架", "取消", true)
}
- 不开新屏幕,只把详情卡片显示出来、其余卡片隐藏,返回时反过来。数据都在同一个屏幕的变量里,不用在屏幕之间传值。
- 只有卖家本人看得到「下架」按钮——但这只是界面上的限制:别人换个同样的昵称,或者直接改服务器上的数据,照样能删。真正的「只有本人能删」需要账号系统,这正是下一步该学的东西。
- 下架前弹确认框,用户选「下架」后才去读列表、删除(「选择完成时」事件)。
跑起来看看
- 发布:表单检查不过会提示原因;发布成功后表单清空,商品出现在商品墙最上面。
- 搜索「自行」:只剩名称里有「自行」的商品;清空搜索词再点搜索,显示全部。
- 点开别人的商品:看大图、价格、描述、卖家,没有「下架」按钮。
- 点开自己的商品:点「下架」→ 确认 → 回到商品墙,这件不见了。
- 关掉服务端再发布:提示连不上,表单内容都还在。
常见问题
| 现象 | 原因与办法 |
|---|---|
| 发布后别人的商品没了 | 没有先读最新列表就写回。所有改列表的操作都要先读 |
| 下架删错了一件 | 按名称或位置删了。要按 id 在最新列表里找 |
| 点详情显示的不是点的那件 | 搜索后列表变短了,要从 显示列表 里取,而不是从 全部 里取 |
| 价格栏粘贴进了文字 | 「仅限数字」只是弹出数字键盘,挡不住粘贴;积木里仍要用「是否为数字」检查 |
| 返回后发布表单不见了 | 「显示详情(false)」里要把三张卡片都设回可见 |
| 别人也能下架我的商品 | 本课的权限只在界面上,见第五步的说明;要真权限请用账号系统 |
动手改一改
- 加一个「只看我发布的」开关,筛选卖家是自己的商品。
- 详情页加「联系卖家」:发布时多填一个微信号或电话,详情页显示出来。
学完以后
恭喜你做完了整个专题!这 5 课用的都是最朴素的「按标签存取」,已经能做出不少多人 App。要继续往上走——注册登录、真正的权限、服务器上查询——请看专题首页最后一节「学完以后」,以及 CloudBase、注册登录教程。
用到的组件
网络微数据库 · Web 客户端 · 图片处理 · 图像选择器 · 列表显示框 · 对话框 · 微数据库
验证范围
最终 .aia 已通过正式编辑器载入与保存重开(0 错误)、后台导入和 Android APK 编译;连真实服务端执行积木检查 30 项(7 种输入校验、上传与登记、他人刚发布后再发布不丢、搜索、详情切换、非卖家看不到下架、确认与取消、已被删掉时的提示、断网保留表单、重启恢复等),见验证记录。真机运行与 AI 伴侣联调尚未测试。
扫码添加客服咨询