diff --git a/index.html b/index.html index 29b11cf..a7d72f0 100644 --- a/index.html +++ b/index.html @@ -7,9 +7,11 @@ 兜爸心选 · 孕育陪伴 - + + + diff --git a/js/app.js b/js/app.js index e12a869..12f245f 100644 --- a/js/app.js +++ b/js/app.js @@ -3,7 +3,7 @@ (function () { 'use strict'; /* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */ - var VER = '26091601'; + var VER = '26091602'; const $ = (s, c) => (c || document).querySelector(s); const $$ = (s, c) => Array.from((c || document).querySelectorAll(s)); @@ -163,6 +163,15 @@ ⚠️ 内置档案屏(#screen-archive)依旧屏蔽:数据来源未确认,不放进一期给用户。 屏的代码/样式全部保留,后续确认数据源后把这里改回 go('archive') 原逻辑即可。 身份转发:把当前 openid/unionid 带过去(query + hash 双写,对齐身份注入惯例)。 */ + /* 换页/换应用前向小程序宿主上报「即将进入的地址」(分享卡片状态同步)。 + 背景:web-view 里的 H5 不能自己拉起分享面板,宿主只能靠 onShareAppMessage(options).webViewUrl + 拿到当前地址,而 onShareTimeline 没有回调参数;首页壳也不会随 H5 换页重新 onLoad。 + postMessage 非实时(微信在「分享 / 后退」等时机才派发),届时 web-view 已停在该地址。 + 协议见 box_app/docs/h5-auth-standard.md 第四节。 */ + function reportHostLocation(url) { + if (window.wxAuth && window.wxAuth.reportLocation) window.wxAuth.reportLocation({ href: url }); + } + function goArchiveH5() { const oid = hashParam('openid'); const uid = hashParam('unionid'); @@ -171,6 +180,7 @@ if (oid) q.push('openid=' + encodeURIComponent(oid)); if (uid) q.push('unionid=' + encodeURIComponent(uid)); if (q.length) u += '?' + q.join('&'); + reportHostLocation(u); location.href = u; } @@ -196,6 +206,7 @@ if (oid) q.push('openid=' + encodeURIComponent(oid)); if (uid) q.push('unionid=' + encodeURIComponent(uid)); if (q.length) url += (url.indexOf('?') >= 0 ? '&' : '?') + q.join('&'); + reportHostLocation(url); location.href = url; } function renderAppGrid(apps) { @@ -4141,6 +4152,8 @@ /* ================= 初始化 ================= */ function init() { + /* 首屏向小程序宿主上报当前位置:宿主据此解析分享卡片(见 reportHostLocation 说明)。 */ + if (window.wxAuth && window.wxAuth.reportLocation) window.wxAuth.reportLocation(); /* 默认预产期是「今天 + 3 个月」现算出来的,标记里那些 「孕 24 周 +3 天 / 预产期 2024年12月22日」只是设计稿留下的占位, 进门先按真实 state 刷一遍,免得首屏闪一下旧数字 */ diff --git a/js/wx-auth.js b/js/wx-auth.js index e849ea0..edd3349 100644 --- a/js/wx-auth.js +++ b/js/wx-auth.js @@ -9,6 +9,10 @@ wxAuth.isAuthorized(); // 是否已授权(手机号/昵称/头像任一非空) wxAuth.requestProfile(); // 点「授权登录」→ postMessage 通知宿主页 wxAuth.goMall(); // 点「进商城」→ 跳小程序商城 tabBar 页 + wxAuth.watchLocation(); // 换页/路由切换自动上报当前位置 → 宿主刷新分享卡片(推荐) + wxAuth.reportLocation({title}); // 手动上报一次当前页(标题/图可选) + 分享卡片同步协议(location/share/setTitle/copyLink/requestProfile)见 + box_app/docs/h5-auth-standard.md 第四节 回传协议:宿主页授权成功后更新 web-view src 为 ?t=#openid=..&phone=..&nickname=..&avatar=.. (微信 webview 丢 query、不丢 hash,故授权结果放 hash) @@ -134,6 +138,65 @@ if (nameEl && a.nickname) nameEl.textContent = a.nickname; if (avatarEl && a.avatar) avatarEl.src = a.avatar; }, + /* ⑦ 上报"当前在哪一页"(分享状态同步,不弹 toast、可频繁调用)。 + 为什么需要:web-view 里的 H5 不能自己拉起分享面板,转发卡片由小程序宿主页产出; + 宿主只有 onShareAppMessage(options).webViewUrl 能拿到当前地址,而 + onShareTimeline(朋友圈)**没有回调参数**;首页壳又不会随 H5 换页重新 onLoad。 + 所以应用在「页面/路由切换」时上报一次 location,宿主即可刷新分享图/标题/深链。 + 协议:{action:'location', href, title?, summary?, imageUrl?} → 详见 docs/h5-auth-standard.md 第四节 + opts.imageUrl 给了就以 H5 为准(仅当前应用);不给则用 box_app 后台配置的分享图。 */ + reportLocation: function (opts) { + opts = opts || {}; + if (!(window.wx && window.wx.miniProgram && window.wx.miniProgram.postMessage)) return false; + try { + window.wx.miniProgram.postMessage({ + data: { + action: 'location', + href: opts.href || location.href, // 可传 href:用于"即将跳转到的地址"上报 + title: opts.title || '', + summary: opts.summary || '', + imageUrl: opts.imageUrl || '' + } + }); + return true; + } catch (e) { + try { console.warn('[wxAuth] reportLocation fail:', e); } catch (e2) {} + return false; + } + }, + /* ⑧ 自动监听页面切换并上报(首屏一次 + hashchange/popstate + pushState/replaceState)。 + 用法(推荐在 init 回调里调用): + wxAuth.watchLocation(function () { + return { title: document.title }; // 可选:本页分享标题/图 + }); + 同一 href 只会发一次(内部去重),SPA 与多页应用都适用。 */ + watchLocation: function (getShare) { + var self = this; + var last = ''; + function pull() { + if (location.href === last) return; + last = location.href; + var s = (typeof getShare === 'function') ? (getShare() || {}) : {}; + self.reportLocation(s); + } + pull(); // 首屏 + if (g.addEventListener) { + g.addEventListener('hashchange', pull); + g.addEventListener('popstate', pull); + } + /* history.pushState/replaceState 不触发上面两个事件,需要包一层 */ + ['pushState', 'replaceState'].forEach(function (fn) { + var orig = g.history && g.history[fn]; + if (typeof orig !== 'function') return; + g.history[fn] = function () { + var r = orig.apply(this, arguments); + setTimeout(pull, 0); + return r; + }; + }); + return self; + }, + toast: function (m) { var t = document.getElementById('toast'); if (!t) return;