Files
mama-box/js/host-nav.js

109 lines
6.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
host-nav.js · 小程序里换页开「容器页」(2026-11-09 用户)
------------------------------------------------------------
「在任何一个子页面点小程序『复制链接』,打开应该进到那个子页面,现在都进首页」——
「复制链接」复制的是**小程序当前页面**的路径和参数。首页壳里 location.href 换页,小程序页面一直是首页壳,
复制出来永远是首页。所以在小程序里进子页面 / 应用 / 广场笔记时,navigateTo 通用容器
pages/annex/web_view/index?url=<净地址>(分享卡片落地用的同一个页,容器按打开者自己的身份注入),
小程序当前页就是那一页。
MBHost.open(url, fallback) 小程序里开容器页;不在小程序 → false(调用方照旧 location.href);
navigateTo 失败(页面栈满 10 层等)→ 调 fallback,没给就 location.href = url
MBHost.back(fallback) 本页是 open() 开出来的容器页(地址带 _hv=1)→ navigateBack 回上一页,返回 true;
后退失败(复制链接直接打开、没有上一页)→ 调 fallback
MBHost.home(fallback) 同上条件 → switchTab 回小程序首页(首页壳是 tabBar 页,原来停的位置还在)
⚠️ url 只放净地址:去掉 openid/unionid/__no_identity/return_url 和 hash 里的身份,复制出去不带分享人身份。
⚠️ 加 _hv=1 只为让页面知道「我在容器页里」,返回时用 navigateBack,不用在容器里再开一个首页。
11-09 二修(用户:「复制链接打开笔记,点左上角返回回不到首页」):复制链接 / 分享卡片直接打开的容器页没有上一页,
navigateBack 不动。open() 换页前在本机记一笔 mbhost.open,新容器页加载时对上了 = 「从上一页点进来的」,
本页 sessionStorage 记 mbhost.child;back() 只有 child 才 navigateBack,否则 switchTab 回小程序首页。
MBHost.onLeave:open() 跳走前调一下(首页用来记滚动位置,宿主回前台重载首页后回到原位置)。
============================================================ */
(function (g) {
'use strict';
if (g.MBHost) return;
var VIEW = '/pages/annex/web_view/index';
var at = 0;
function mp() { return g.wx && g.wx.miniProgram; }
function inMp() { return g.__wxjs_environment === 'miniprogram' || /miniProgram/i.test(navigator.userAgent); }
function inView() { return /[?&]_hv=1(&|$)/.test(location.search); }
var OK = 'mbhost.open', CK = 'mbhost.child';
function key(href) { /* 比对用:去掉容器注入的身份 / 时间戳参数 */
var u = new URL(href, location.href);
['openid', 'unionid', 't', '_v', '__no_identity'].forEach(function (k) { u.searchParams.delete(k); });
u.searchParams.sort && u.searchParams.sort();
return u.pathname + u.search;
}
function isChild() { try { return sessionStorage.getItem(CK) === '1'; } catch (e) { return false; } }
(function () {
if (!inView()) return;
try {
var m = JSON.parse(localStorage.getItem(OK) || 'null');
if (m && Date.now() - m.at < 30000 && key(m.u) === key(location.href)) { sessionStorage.setItem(CK, '1'); localStorage.removeItem(OK); }
} catch (e) {}
})();
function toHome(fallback) {
var m = mp();
if (!m || typeof m.switchTab !== 'function') { if (fallback) fallback(); return; }
m.switchTab({ url: '/pages/index/index', fail: function () {
if (typeof m.reLaunch === 'function') m.reLaunch({ url: '/pages/index/index', fail: function () { if (fallback) fallback(); } });
else if (fallback) fallback();
} });
}
function clean(url) {
var u = new URL(url, location.href);
['openid', 'unionid', '__no_identity', 'return_url', 'norestore'].forEach(function (k) { u.searchParams.delete(k); });
if (/(^|[#&])(openid|unionid|phone|nickname|avatar|norestore)=/.test(u.hash)) u.hash = '';
u.searchParams.set('_hv', '1');
return u.href;
}
var H = {
inMp: inMp,
inView: inView,
isChild: isChild,
onLeave: null,
open: function (url, fallback) {
var m = mp();
if (!inMp() || !m || typeof m.navigateTo !== 'function') return false;
if (Date.now() - at < 1000) return true; // 连点:上一次 navigateTo 还在路上
var c;
try { c = clean(url); } catch (e) { return false; }
at = Date.now();
try { if (typeof H.onLeave === 'function') H.onLeave(); } catch (e) {}
try { localStorage.setItem(OK, JSON.stringify({ u: c, at: at })); } catch (e) {}
m.navigateTo({
url: VIEW + '?url=' + encodeURIComponent(c),
fail: function () { at = 0; if (fallback) fallback(); else location.href = url; }
});
return true;
},
back: function (fallback) {
var m = mp();
if (!inView() || !inMp() || !m || typeof m.navigateBack !== 'function') return false;
if (isChild()) m.navigateBack({ delta: 1, fail: function () { toHome(fallback); } });
else toHome(fallback); /* 复制链接 / 分享直接打开:没有上一页 → 回小程序首页 */
return true;
},
home: function (fallback) {
var m = mp();
if (!inView() || !inMp() || !m || typeof m.switchTab !== 'function') return false;
toHome(fallback);
return true;
}
};
g.MBHost = H;
/* 页面里的 <a href> 指向本站别的页面:小程序里也开容器页(别人已经 preventDefault 的不管) */
document.addEventListener('click', function (e) {
if (e.defaultPrevented || e.button || e.metaKey || e.ctrlKey || !inMp()) return;
var a = e.target && e.target.closest && e.target.closest('a[href]');
if (!a || a.target || a.hasAttribute('download')) return;
var href = a.getAttribute('href') || '';
if (!href || href.charAt(0) === '#' || /^(javascript|mailto|tel):/i.test(href)) return;
var u;
try { u = new URL(href, location.href); } catch (err) { return; }
if (u.origin !== location.origin || u.pathname === location.pathname) return;
if (H.open(u.href)) e.preventDefault();
});
})(window);