ByteNoteByteNote
空列表也会把分享交出去
字

字节笔记本

2026年10月7日 · 约 9 分钟读完

空列表也会把分享交出去

API中转
¥120

首页用一份 JSON5 路由声明成 type="home",导航样式是 custom。列表在页面显示时去拉 /private/daily。分享按钮是 open-type="share",真正发出去的路径要等创建接口返回 share_id。列表是空的时候,提示出现了,请求仍会发出去。

分享前先确认这一天有没有音频

显示时拉列表,添加走另一页

路由块写在文件顶上,lang="json5",允许注释。navigationBarTitleText 是首页。模板是一个 scroll-view,按天渲染卡片。没有记录时文案是暂无记录。有记录时每条交给 TrackPlayer,标题、音频 id 和地址分别来自 title、id、url。id 在绑定前被收成字符串。

onShow 里发 GET /private/daily,成功后把 res.data 放进 dailyData。显示时拉,而不是只在第一次加载时拉,从创建页返回才会看到新的一天。失败分支样本里没有写。请求工具和 showErrorToast 从工具模块引进。onShareAppMessage 从 @dcloudio/uni-app 引进。onShow 在这段脚本里被调用,文件头部却没有把它和分享钩子写在同一行导入里。若项目没有自动导入,这里会在运行前就报未定义。

去打卡和卡片上的加号都进 handleAdd,uni.navigateTo 到 /pages/daily-create/daily-create。样本里的 console.log 只说明点到了,不参与跳转。

分享依赖上一次点到的那一天

分享按钮同时绑了 open-type="share" 和 handleShare(day)。点击时把这一天存进 item。随后平台调用 onShareAppMessage。里面先 createShare:用 item.value.list 取出每条音频的 id。长度为 0 时 showErrorToast,文案是请先录制音频。提示之后没有返回,函数继续 POST /private/share/create,正文是 { ids }。空数组也会被提交。

提示之后应当返回,不要再请求。接口若拒绝空数组,用户会先看到提示,再看到一次失败。接口若收下空数组,会得到一个没有音频的分享。两种都不是“请先录制”想要的停住。

请求回来之后,样本又等了 500 毫秒,然后返回分享配置。标题用本地存储里的 userInfo.username,拼上 item.value.date 和打卡二字。路径是 /pages/share/share?shareId= 加上 res.data.share_id。等待的那半秒没有换数据,只是拖时间。分享配置仍应在 share_id 已经拿到之后再返回。没拿到 id 就返回路径,对方打开的是空查询。

title 是一个计算属性,读取存储和 item。分享若发生在 handleShare 写入之前,日期会是空的。按钮把写入和 open-type 放在同一次点击上,写入是同步的,一般会先发生。不要把 item 改成在分享钩子里再去猜“当前天”。钩子只读已经点中的那一天。

空列表提示之后必须停住

颜色和结构分开

卡片标题条用了类 bg-wechat,样式里把它收成 #00B26A。其余间距、圆角、字号走工具类。分享图标和添加图标是本地 svg。播放器组件不在这一页里实现,这一页只负责把 src 传下去。

把这一页收成三件事。显示时 GET 每日列表。添加只负责跳到创建页。分享先记住被点的那一天,没有音频就停,有音频才 POST 换 share_id,再把带查询的路径交回去。500 毫秒的等待不代替 id 是否存在的判断。用户名来自本地存储,存储里没有 userInfo 时标题会在读取上失败,分享前要先确认这份存储在。

空列表时请求仍然发出

把一次分享按时间摊开。用户点到某一天,handleShare 把 day 放进 item。平台接着调用 onShareAppMessage。createShare 读取 item.value.list,映射出 id。长度为 0 时弹出请先录制音频。函数没有 return,下一行仍是 POST /private/share/create,正文 { ids: [] }。服务端若校验 ids 不能为空,用户会看到提示,紧接着再看到一次失败。服务端若不校验,会落下一行没有音频的分享,share_id 仍然返回。路径 /pages/share/share?shareId= 拼上这个 id,对方打开的是空内容。提示的目的是停住,所以空列表必须在请求前返回。

有录音时,id 来自 TrackPlayer 用过的同一份 id。列表项在模板里把 id 收成字符串。创建分享时若直接传数字,而列表里已经是字符串,服务端按一种类型解析就会对不上。映射时保持和列表一致。样本只写了 item.value.list.map,没有写字段名变换。字段若不是 id,映射结果是空或未定义,长度却不为 0,请求会带上无效值。空数组和无效 id 是两种失败,都要在 POST 前挡住。

标题依赖本地存储

分享标题读 uni.getStorageSync('userInfo') 的 username,再拼日期和打卡。存储里没有这份对象时,读取 username 会在返回分享配置之前抛错,路径也不会带上 share_id。创建页和首页是两条路由,登录态存在存储里才能让标题完整。不要在标题里写死某个人的名字。日期来自被点中的 item.value.date,不是当天的系统日期。点的是昨天,标题就应是昨天。若改成 new Date(),分享出去的日期和卡片对不上。

500 毫秒的等待放在接口返回之后。它不检查 res.data.share_id 是否存在。接口返回错误结构时,等待结束仍会去拼路径,查询变成 undefined。应先看 share_id,没有就不要返回分享配置。等待不能代替这个判断。

onShow 的 GET 和分享的 POST 用的不是同一条路径。返回首页会刷新列表,不会刷新已经发出去的 share_id。对方打开的分享页读的是创建时写入的 ids。后来在这一天再录一条,旧分享不会自动带上新音频,除非重新点分享、重新 POST。这是创建接口的语义,不是列表接口的语义。

首页的 type="home" 只决定它是入口页。分享路径指向 /pages/share/share,那一页要在路由表里单独存在。本文件没有那一页的实现。shareId 查询要由那一页去读。首页只负责把 id 放进路径。

创建分享时映射的是 item.value.list 上每一项的 id。item 初始是空对象。分享若发生在 handleShare 写入之前,list 不存在,.map 会先抛错,走不到长度为 0 的提示。按钮把写入和 open-type 放在一次点击里,正常顺序是先写入。不要在别的入口直接触发分享钩子,否则读到的是初始空对象。

列表为空时文案是暂无记录,这和分享前的提示不是同一句。暂无记录只渲染在卡片里。请先录制音频来自 showErrorToast。两句都出现,说明空状态被看到了,请求仍可能已经发出。修的位置在 if (ids.length === 0) 后面补上返回,而不是改文案。

播放器收到的 audio-id 是 track.id 拼上空字符串。分享提交的 ids 仍是原来的 id。一边字符串、一边原类型,服务端若只认一种,播放和分享会有一个对不上。提交前不要再做一次无谓的类型变换。页面只负责把列表里的 id 原样放进 ids。

绿色是 #00B26A,去打卡按钮的背景是另一段内联的 #F6F6FF。两处颜色不要收成同一个类。分享图标和添加图标路径分别是 /static/images/share.svg 与 add.svg。图标缺失只影响显示,不改变分享是否 POST。 分享配置里的 title 是计算属性,读取存储和当前 item。日期用的是卡片上的 day.date,不是调用时的系统时间。点开昨天的分享,标题里应仍是昨天。用户名只来自 userInfo,存储缺失时计算属性会在返回路径之前失败,share_id 也不会被拼上。首页声明了 type="home",分享路径却指向 /pages/share/share。那一页不在本文件里,它要自己读查询参数 shareId。本页只保证 POST 成功之后才把 id 放进路径。

相关文章

分享: