Files
lucky_shop/main.js
ZF sun a2066285cd feat(mp-weixin): 新增全局兜底分享mixin与路径复制能力
为微信小程序端添加全局分享兜底支持,为所有未显式声明分享钩子的页面提供默认转发和朋友圈分享能力,同时新增小程序路径复制工具方法。
2026-07-11 15:19:26 +08:00

204 lines
7.6 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.
// #ifdef H5
import './common/js/pc'
// #endif
import Vue from 'vue'
import App from './App'
import store from './store'
import Util from './common/js/util.js'
import Http from './common/js/http.js'
import Lang from './common/js/lang.js'
import Config from './common/js/config.js'
import EventBus from './common/js/event-bus.js'
import DomEventBridge from './common/js/dom-event-bridge.js'
import globalConfig from './common/js/golbalConfig.js';
import {
uniStorage
} from './common/js/storage.js'
import configExternal from './common/js/config-external.js'
import PrivacyManager from './common/js/privacy.js'
import splashState from './common/js/splash-state.js'
import ThemeOverride from './common/js/theme-override.js'
Vue.prototype.$store = store //挂在vue
Vue.config.productionTip = false
Vue.prototype.$util = Util;
Vue.prototype.$api = Http;
Vue.prototype.$langConfig = Lang; //语言包对象
Vue.prototype.$lang = Lang.lang; //解析语言包
Vue.prototype.$config = Config;
Vue.prototype.$privacy = PrivacyManager; //全局隐私管理器
// #ifdef H5
EventBus.setDomBridge(DomEventBridge)
// #endif
Vue.prototype.$eventBus = EventBus;
Vue.mixin(globalConfig);
// #ifdef MP-WEIXIN
// 全局兜底分享 mixin:
// 为所有未显式声明 onShareAppMessage / onShareTimeline 的页面提供默认实现,
// 保证"全页面都支持转发 / 朋友圈 / 复制路径"。
// - 已显式声明的页面优先级更高(uni-app 规范),不受影响
// - 后端 /weapp/api/weapp/share 提供标题 / 封面,失败时退化到站点名 + 当前路径
import MpShareDefault from './common/js/mp-share-default.js';
Vue.mixin(MpShareDefault);
// #endif
// 远端 i18n 翻译热更新:复用项目原有"componentRefresh"机制(同 diy.js 下拉刷新)
// lang.js 在翻译覆写更新时 commit('setComponentRefresh'),
// golbalConfig.js 已把 componentRefresh 注册为全局 computed,
// 在此 watch 它并 $forceUpdate,触发所有页面内 {{$lang('xxx')}} 重新求值
Vue.mixin({
watch: {
componentRefresh() {
this.$forceUpdate();
}
}
});
// 鸿蒙元服务环境: 全局接管 onTabItemTap, 兜底系统 TabBar 点击
// 背景: 鸿蒙下 uni.switchTab 对系统 TabBar 点击静默失败
// 通过全局 mixin 覆盖所有未显式定义 onTabItemTap 的页面(子包动态 tab 页等),
// 显式定义 onTabItemTap 的页面(如 pages/empty/index.vue、index.js)优先级高于此 mixin
// #ifdef MP-HARMONY
Vue.mixin({
onTabItemTap(e) {
console.log('[TabBar][HARMONY] global onTabItemTap fired:', e);
if (!e || !e.pagePath) return;
const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
const currentPath = currentPage ? '/' + currentPage.route : '';
const targetPath = e.pagePath.startsWith('/') ? e.pagePath : '/' + e.pagePath;
console.log('[TabBar][HARMONY] onTabItemTap currentPath=', currentPath, 'targetPath=', targetPath);
// 已经在目标页则不重复跳转
if (currentPath === targetPath) return;
// 用干净路径(不带 query), 避免 HarmonyOS 对带 query 的 tabBar 跳转有兼容性问题
uni.reLaunch({
url: targetPath,
success: () => console.log('[TabBar][HARMONY] global reLaunch success:', targetPath),
fail: (err) => console.error('[TabBar][HARMONY] global reLaunch fail:', targetPath, err)
});
}
});
// #endif
App.mpType = 'app';
// 重写存储,增加前缀
uniStorage();
// 组件已改为按需引入,不再全局注册
// ============================================================
// 平台差异处理:
// H5: 可在 $mount() 前 await boot, 首屏直接有翻译
// 小程序/鸿蒙: App() 必须同步注册, $mount() 不能推迟
// → 同步 $mount() + lang() 短路返回空串 + boot 完成后 $forceUpdate
//
// 以下代码所有平台共享:
// - lang.js: bootCompleted 标志, boot 未完成时 lang() 返回空串
// - http.js: sendRequest 门控, boot 未完成时业务请求排队
// - splash-state.js: 统一启动屏状态 (H5 降级 uni.showLoading, 小程序/鸿蒙走 splash 组件)
// - App.vue: onLaunch 中 splashState.show() + await boot + splashState.hide()
// ============================================================
// #ifdef H5
// H5: remote-only 下先 await boot 再 $mount(), 首屏直接有翻译数据
// splashState.show() 内部 H5 降级为 uni.showLoading (await 期间 Vue 还没挂载,组件层无法渲染)
async function bootstrap() {
if (Lang.isRemoteOnly && Lang.isRemoteOnly()) {
splashState.show();
try {
// 1) i18n: 拉远端语言包 (langConfig.source === 'remote-only')
await Lang.boot();
// 2) theme: 阻塞式预热 brand 桶覆写 (themeConfig.overrideRemote.source)
await ThemeOverride.boot();
// 3) theme(remote-only): 异步拉全量 8 个 preset 替换 stub
// 失败静默, 兜底用 webpack stub(只含 default),首屏不白屏
ThemeOverride.loadAllPresets().catch((e) => {
console.warn('[theme-presets] load fail', e);
});
} catch (e) {
console.warn('[i18n] remote-only boot fail', e);
} finally {
splashState.hide({ reason: 'boot-complete' });
}
}
const app = new Vue({
...App,
store
});
app.$mount();
setupResizeListener();
}
bootstrap()
// #endif
// #ifndef H5
// 小程序/鸿蒙: 同步 $mount(), boot 在 App.vue onLaunch 中异步执行
// lang() 在 boot 未完成时返回空串, boot 完成后 emitUpdated 触发 $forceUpdate
const app = new Vue({
...App,
store
});
app.$mount();
// #endif
// ============================================================
// 窗口尺寸变化监听
// ------------------------------------------------------------
// 背景: themeColorSet 会把 token 中的 rpx 转 px,转比例基于 window.innerWidth/750
// 缓存 key 已含 window.innerWidth,所以 cacheKey 不匹配时会自动重算;
// 但需要 resize 事件触发一次 themeColorSet 才会让 cacheKey 重新计算。
//
// 兼容点: 不同发布产物的 resize 来源不一样
// 1. 优先用 uni.onWindowResize — uni-app 跨端 API, H5 / App-Plus 支持
// 2. 兜底用 window.addEventListener('resize') — 纯 H5 产物中直接可用
// 3. 全部 try-catch,某条路径失败不影响其他路径
// 4. 用 200ms 去抖,避免拖动窗口时频繁触发(实测连续 resize 事件可达 60fps)
//
// 调用时机: 仅 H5 端在 $mount() 之后调用;小程序/鸿蒙端
// - 微信小程序: 屏幕尺寸由设备决定,运行时不会变化,无需监听
// - 鸿蒙: 待验证,目前不在这里注册以避免在不支持的环境下抛错
// ============================================================
function setupResizeListener() {
let resizeTimer = null;
const fire = () => {
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
resizeTimer = null;
try {
store.dispatch('themeColorSet');
} catch (e) {
console.warn('[theme] resize -> themeColorSet fail', e);
}
}, 200);
};
// 路径 1: uni 跨端 API(H5 / App-Plus 上有效)
try {
if (typeof uni !== 'undefined' && typeof uni.onWindowResize === 'function') {
uni.onWindowResize(fire);
}
} catch (e) {
console.warn('[theme] uni.onWindowResize bind fail', e);
}
// 路径 2: 原生 window resize 事件(H5 兜底,某些自定义 H5 产物可能没装 uni)
try {
if (typeof window !== 'undefined' && typeof window.addEventListener === 'function') {
window.addEventListener('resize', fire);
}
} catch (e) {
console.warn('[theme] window.resize bind fail', e);
}
}