feat(mp-share): add disabled share page list and hide share menu for specific pages

新增了禁用分享的页面配置列表,针对指定页面主动隐藏转发按钮,同时优化了分享逻辑的兜底和性能。
具体包括:
1. 增加_DISABLED_PAGES集合管理禁分享页面路由
2. 添加页面禁用检查和隐藏分享菜单工具方法
3. 在created和onLoad阶段自动隐藏对应页面的转发按钮
4. 优化onShow和分享钩子的禁用逻辑,避免无效请求和调用
This commit is contained in:
2026-07-15 09:05:50 +08:00
parent cb5878ad29
commit 00bf4bcfd6

View File

@@ -30,6 +30,68 @@ const _safeGetCurrentPage = () => {
}
};
/**
* 关闭分享能力的页面 route 列表(不带前导斜杠,与 mp-weixin page.route 保持一致)
*
* 为什么需要:
* mp-share-default.js 通过 Vue.mixin 全局注入 onShareAppMessage / onShareTimeline,
* 但有些页面不适合"分享":
* 1) webview 容器页: 转发它等于转发一个 iframe 壳,无意义且会暴露内部 src
* 2) 隐私弹窗 / 登录中转页: 状态不稳定,转出去体验差
* 3) 任何业务明确要求"不分享"的页面
*
* 命中后行为:
* - mixin 内部不再拉取分享配置(节省一次 HTTP 请求)
* - mixin 注入的 onShareAppMessage / onShareTimeline / $mpShare_* 工具方法仍然存在,
* 但内部立即调用 wx.hideShareMenu() 把转发按钮从右上角菜单中隐藏
* - 这两条防线双保险:即使 mixin 钩子被业务侧转发链路误触发,也不会显示分享弹窗
*
* 备选方案对比(都没选,原因列在下方):
* - 在 created 里 this.onShareAppMessage = undefined:
* Vue mixin 合并策略会把 undefined 视为"未声明",mixin 的钩子仍然生效 → 不可靠
* - mixin 内 return null / 不 return:
* 微信会回退到默认 title 转发,按钮仍显示 → 不可靠
* - 使用 wx.hideShareMenu(本方案采用):
* 微信官方 API,会立即把"转发"按钮从当前页右上角菜单中隐藏,行为最稳
*/
const _DISABLED_PAGES = new Set([
'pages_tool/webview/webview', // webview 容器,转发无意义
]);
const _isCurrentPageDisabled = () => {
const page = _safeGetCurrentPage();
if (!page) return false;
const route = (page.route || (page.$page && page.$page.path) || '').replace(/^\//, '');
return _DISABLED_PAGES.has(route);
};
/**
* 主动隐藏当前页的"转发"按钮
* - 只能在 mp-weixin 环境调用(其它平台 wx 全局不存在)
* - 必须在 onLoad 之后调用(需要 Page 实例已注册完成)
* - 失败时静默吞掉(权限/版本/非微信环境都可能导致失败)
*/
const _hideShareMenu = () => {
try {
// #ifdef MP-WEIXIN
if (typeof wx !== 'undefined' && typeof wx.hideShareMenu === 'function') {
wx.hideShareMenu({
menus: ['shareAppMessage', 'shareTimeline']
});
}
// #endif
} catch (e) {
// 静默:旧基础库可能不支持 menus 参数,降级到无参版本
try {
// #ifdef MP-WEIXIN
if (typeof wx !== 'undefined' && typeof wx.hideShareMenu === 'function') {
wx.hideShareMenu();
}
// #endif
} catch (e2) { /* ignore */ }
}
};
const _getCurrentPath = (withQuery = true) => {
const page = _safeGetCurrentPage();
if (!page) return '';
@@ -90,11 +152,30 @@ export default {
__mpShareCache: null, // 当前页面的分享配置
};
},
/**
* 在实例创建阶段检查当前页面是否在 _DISABLED_PAGES 列表中。
* 命中后调用 wx.hideShareMenu 把当前页的"转发"按钮从右上角菜单中隐藏。
*/
created() {
try {
if (_isCurrentPageDisabled()) {
// 立即隐藏(此时 wx 还没完全就绪,先尝试一次;失败也无所谓,onLoad 会再调一次)
_hideShareMenu();
}
} catch (e) {}
},
onLoad() {
try {
if (_isCurrentPageDisabled()) {
// 命中关闭列表的页面:
// 1) 再次调 wx.hideShareMenu(此时 Page 已就绪,稳定生效)
// 2) 不再拉取分享配置,避免无谓请求
_hideShareMenu();
return;
}
const path = _getCurrentPath(true);
_getShareConfig(path).then(cfg => {
// 后端未返回配置时,注入站点名作为默认标题
// 后端未返回配置时,注入站点名作为默认标题
if (cfg && !cfg.title) {
const siteName = (this.$store && this.$store.state && this.$store.state.siteInfo && this.$store.state.siteInfo.site_name) || '';
cfg.title = siteName || '小程序分享';
@@ -104,21 +185,27 @@ export default {
} catch (e) {}
},
onShow() {
// 兜底:进入页面后如果尚未就绪,再异步拉一次
if (!this.__mpShareCache) {
try {
const path = _getCurrentPath(true);
_getShareConfig(path).then(cfg => {
this.__mpShareCache = cfg;
});
} catch (e) {}
}
// 兜底:进入页面后如果尚未就绪,再异步拉一次
if (this.__mpShareCache) return;
if (_isCurrentPageDisabled()) return; // 命中关闭列表,不再拉
try {
const path = _getCurrentPath(true);
_getShareConfig(path).then(cfg => {
this.__mpShareCache = cfg;
});
} catch (e) {}
},
/**
* 全局默认 onShareAppMessage:
* uni-app 规范:组件自身的钩子优先级 > mixin,因此已显式声明的页面不受影响。
* 全局默认 onShareAppMessage:
* uni-app 规范:组件自身的钩子优先级 > mixin,因此已显式声明的页面不受影响。
*/
onShareAppMessage() {
// 命中禁用列表的页面:即使 wx.hideShareMenu 因某些原因没生效,
// 这里直接 return undefined / 也不主动拼 cfg,让微信回退到默认行为
// (主防线是 wx.hideShareMenu,这里只是兜底)
if (_isCurrentPageDisabled()) {
return undefined;
}
const cfg = this.__mpShareCache;
if (cfg && cfg.title) {
return {
@@ -127,17 +214,20 @@ export default {
imageUrl: cfg.imageUrl || ''
};
}
// 后端无配置时:使用站点名 + 当前路径
// 后端无配置时:使用站点名 + 当前路径
return {
title: _buildFallback(_getCurrentPath(true)).title,
path: _getCurrentPath(true)
};
},
/**
* 全局默认 onShareTimeline(朋友圈):
* 朋友圈只支持 query(不能直接传 path),从 cfg.path 中抽取 ? 之后的 query。
* 全局默认 onShareTimeline(朋友圈):
* 朋友圈只支持 query(不能直接传 path),从 cfg.path 中抽取 ? 之后的 query。
*/
onShareTimeline() {
if (_isCurrentPageDisabled()) {
return undefined;
}
const cfg = this.__mpShareCache;
if (cfg && cfg.title) {
const path = cfg.path || _getCurrentPath(true);