
字节笔记本
2026年10月7日 · 约 9 分钟读完
分享页再点一次,为什么不走 onLoad
从聊天里第一次点开分享卡片,页面会走 onLoad、onShow、onReady。小程序还没被系统杀掉时,再点同一条卡片,往往只剩 onShow。参数如果只在 onLoad 里读一次、又不存下来,第二次进来页面还在,数据却像没带上查询参数。

第一次才有 onLoad
冷启动打开分享路径时,顺序是加载、显示、初次渲染完成。onLoad 的参数就是路径上的查询。分享函数把路径写成带 id 的地址:
onShareAppMessage() {
return {
title: "分享标题",
path: "/pages/share/share?id=123",
}
}接收端在 onLoad(options) 里看到 options.id。扫码进来时,参数有时在 options.scene 里,而且是编码过的,要先 decodeURIComponent。分享进来和扫码进来不要用同一个字段判断。有 scene 按扫码处理,有 id 按分享处理。两个都没有,就是普通打开。
pages.json 里对应页要允许分享,样式里的 enableShare 设为 true。没开这个开关,右上角可能没有分享,生命周期讨论也无从开始。
onShareAppMessage 的参数能区分来源。res.from === "button" 是页面里的按钮,其余按右上角菜单。两条路径可以返回不同的标题和 path。按钮分享用当前记录的 id,菜单分享可以回到首页。不要两条都写死同一个 path,否则无法从按钮把某条记录发出去。
进程还在时,再点同一条只走 onShow
同一条分享在聊天里多点几次,应用进程如果还在,页面实例可能被直接显示出来,而不是重新创建。这时 onLoad 不会再来。测试可以做成两个提示:onLoad 里弹一次“加载”,onShow 里弹一次“显示”。开发者工具里反复点同一条链接,控制台往往只有显示。
所以参数要在第一次 onLoad 时存进页面数据,例如 pageQuery。之后每次 onShow 用这份存下来的参数做刷新,而不是再读一次 options。onShow 没有那份首次参数。
onLoad(options) {
this.pageQuery = options
this.initData(options)
},
onShow() {
this.refreshPageData()
}刷新函数里如果正在请求,用一个开关挡着重入。分享页被快速切走又切回时,onShow 会连着来,两个请求叠在一起会把旧数据写回新界面。
script setup 要从 uni-app 里引入
Vue 3 的 script setup 没有选项式的 onLoad 字段。页面生命周期从 @dcloudio/uni-app 引入:onLoad、onShow、onHide。它们是函数,在 setup 里直接调用注册。组件挂载用 Vue 的 onMounted,不要用它代替 onLoad。onMounted 拿不到路由参数,也没有“每次显示”的语义。
样本把 onShareAppMessage 放进了 defineExpose。defineExpose 是把方法暴露给父组件,不是注册页面的分享回调。页面要能被转发,分享函数仍然要按页面生命周期注册,而不是只暴露出去。按钮和菜单的区分逻辑不变,变的是注册位置。
完整顺序里,Vue 的 beforeCreate、created 会早于页面的 onLoad。onReady 表示初次渲染完成,和 onLoad 一样只来一次。重复进入分享不该指望 onReady 再跑初始化。初始化放 onLoad,刷新放 onShow。
参数存下来,刷新放在 onShow
分享路径上的 id 只在第一次 onLoad 里可靠出现。进程没销毁时再点同一条,只有 onShow。把 options 存进页面,刷新走这份副本。script setup 用 uni-app 提供的生命周期函数注册。分享回调不要只放在 defineExpose 里。

分享按钮和右上角不是同一条 path
按钮分享要带当前记录的 id,菜单分享可以是首页。如果两支都返回同一个 path,用户从按钮发出去的卡片打开后没有 id,onLoad 里的分支会走到普通打开。测试时看卡片上的路径,不要只看 onShareAppMessage 有没有被调用。
success 回调写在返回对象里,用来提示分享成功。它不等于对方已经打开。对方打不开、或打开时小程序被杀掉,是接收端的生命周期,发送端的 success 不会再来一次。接收端该做的初始化不要写在发送端的 success 里。
scene 和 id 的判断要互斥且可解释。扫码的 scene 解码后可能仍是一个自定义字符串,不一定叫 id。分享查询用的是 path 上你自己写的键。文档里不要把所有入口都叫 scene。样本把有 scene 当作扫码,有 id 当作分享,这是针对那一种路径设计的,换了参数名就要改条件。
onHide 在切到后台时触发。从分享卡片回到聊天,再点一次,如果进程还在,顺序是 onHide 之后再 onShow,中间没有 onLoad,也没有 onReady。刷新请求放在 onShow 是对的,但要允许用户只是切出去看了一眼。可以用上次显示时间做很短的节流,避免每次 onShow 都打满接口。节流不能长到让新参数永远不刷新。参数变了必须更新,这就又回到“进程被杀掉时 onLoad 会带来新 options”。
options 里的值是字符串。id 为 123 在路径上,取出来是 "123"。和数字比较之前要转换。不做转换,条件永远不成立,表现得像没走进分享分支。
Vue 选项式里 onLoad 写在导出对象上。script setup 里改成从包里引入的函数之后,不要两套都留。留两套时,有的构建只会执行其中一套,参数存进了一个实例、刷新读的是另一个。页面只保留 script setup 这一套,初始化函数接收 options 并写入 ref。 开发者工具的编译模式和真机不完全一样。工具里进程经常不被杀,所以很容易复现“只有 onShow”。真机上切到别的应用再回来,系统可能已经回收,这时 onLoad 会再来,options 是新的一次打开。两种都要测。只在工具里测,会把“必须存参数”当成永远不需要读新 options。只在真机冷启动测,会看不见 onLoad 缺失的那个坑。
分享图片 imageUrl 是可选的。不填时用页面截图,填了就要是可访问的地址。地址失效不会改变生命周期,但会让人以为分享没发出去,从而不去测第二次点击。生命周期测试先用默认图,路径上只保留 id。
页面栈里如果分享路径不是重新打开,而是返回已有页,onShow 同样会来,onLoad 不来。和聊天里重复点卡片是同一类现象。刷新逻辑写在 onShow,两种入口都覆盖。初始化写在 onLoad,只覆盖新实例。 onReady 只适合做依赖节点尺寸的事,例如量一下画布。数据请求不要等它。重复进入时它不执行,等它的请求就不会再刷新。分享页的数据以 onLoad 初始化、onShow 刷新为准,渲染完成只做和节点有关的收尾。
参数存进 ref 或 data 之后,模板如果直接显示 id,可以用来肉眼确认第二次进入值还在。值还在但列表是旧的,说明 onShow 没有用这份参数去请求。值没了,说明存的位置在页面复用时被重置。两种日志一打就分开了。 冷启动和热启动各测一次就够写进检查单。冷启动看 onLoad 是否拿到 id 并完成初始化。热启动看 onShow 是否用保存的 id 刷新,而不是空白参数去请求。两条都通过,分享页的生命周期才算接上。只通过一条,列表会在某一种打开方式下是空的。



