// src/hooks/useWechatShare.js // 微信分享 Hook - 支持自动配置右上角分享菜单和显式分享引导 import { useState, useEffect, useCallback, useRef } from 'react'; import { getJsSdkConfig } from '@services/miniprogramService'; /** * 检测是否在微信浏览器中 */ const isWechatBrowser = () => { const ua = navigator.userAgent.toLowerCase(); return ua.includes('micromessenger'); }; /** * 微信分享 Hook * * @param {Object} options - 分享配置 * @param {string} options.title - 分享标题 * @param {string} options.desc - 分享描述 * @param {string} options.link - 分享链接(默认当前页面) * @param {string} options.imgUrl - 分享图标 URL * @param {boolean} options.autoSetup - 是否自动配置分享(默认 true) * * @returns {Object} 分享状态和方法 */ const useWechatShare = (options = {}) => { const { title = '', desc = '', link = '', imgUrl = '', autoSetup = true, } = options; const [isReady, setIsReady] = useState(false); const [isInWechat, setIsInWechat] = useState(false); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(false); // 使用 ref 存储最新的分享配置,避免重复初始化 const shareConfigRef = useRef({ title, desc, link, imgUrl }); const isInitializedRef = useRef(false); // 更新 ref 中的配置 useEffect(() => { shareConfigRef.current = { title, desc, link, imgUrl }; // 如果已初始化且配置变化,更新分享内容 if (isReady && isInWechat && window.wx) { updateShareData(); } }, [title, desc, link, imgUrl, isReady, isInWechat]); /** * 更新分享数据 */ const updateShareData = useCallback(() => { if (!window.wx || !isReady) return; const config = shareConfigRef.current; const shareLink = config.link || window.location.href.split('#')[0]; // 分享给朋友 window.wx.updateAppMessageShareData({ title: config.title || document.title, desc: config.desc || '', link: shareLink, imgUrl: config.imgUrl || `${window.location.origin}/logo192.png`, success: () => { console.log('[WechatShare] updateAppMessageShareData 设置成功'); }, fail: (err) => { console.error('[WechatShare] updateAppMessageShareData 失败:', err); } }); // 分享到朋友圈 window.wx.updateTimelineShareData({ title: config.title || document.title, link: shareLink, imgUrl: config.imgUrl || `${window.location.origin}/logo192.png`, success: () => { console.log('[WechatShare] updateTimelineShareData 设置成功'); }, fail: (err) => { console.error('[WechatShare] updateTimelineShareData 失败:', err); } }); }, [isReady]); /** * 初始化微信 JS-SDK */ const initWxSdk = useCallback(async () => { if (isInitializedRef.current || !isInWechat) return; setIsLoading(true); setError(null); try { // 获取当前页面 URL(不含 hash) const currentUrl = window.location.href.split('#')[0]; // 获取 JS-SDK 签名配置 const config = await getJsSdkConfig(currentUrl); if (!config) { throw new Error('获取签名配置失败'); } // 配置微信 JS-SDK window.wx.config({ debug: false, // 生产环境关闭 appId: config.appId, timestamp: config.timestamp, nonceStr: config.nonceStr, signature: config.signature, jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'], }); // 监听 ready 事件 window.wx.ready(() => { console.log('[WechatShare] wx.ready 触发'); isInitializedRef.current = true; setIsReady(true); setIsLoading(false); // 自动设置分享内容 if (autoSetup) { updateShareData(); } }); // 监听 error 事件 window.wx.error((err) => { console.error('[WechatShare] wx.error:', err); setError(err.errMsg || '微信 JS-SDK 初始化失败'); setIsLoading(false); }); } catch (err) { console.error('[WechatShare] 初始化失败:', err); setError(err.message || '初始化失败'); setIsLoading(false); } }, [isInWechat, autoSetup, updateShareData]); // 检测微信环境并初始化 useEffect(() => { const inWechat = isWechatBrowser(); setIsInWechat(inWechat); if (inWechat && autoSetup) { // 确保 wx 对象已加载 if (window.wx) { initWxSdk(); } else { // 等待 wx 对象加载 const checkWx = setInterval(() => { if (window.wx) { clearInterval(checkWx); initWxSdk(); } }, 100); // 3秒后停止检查 setTimeout(() => clearInterval(checkWx), 3000); } } }, [autoSetup, initWxSdk]); /** * 手动触发分享引导 * 在微信中会提示用户点击右上角分享 * 在非微信环境中可以展示其他分享方式 */ const triggerShare = useCallback(() => { if (!isInWechat) { // 非微信环境,可以使用 Web Share API 或复制链接 if (navigator.share) { navigator.share({ title: shareConfigRef.current.title || document.title, text: shareConfigRef.current.desc, url: shareConfigRef.current.link || window.location.href, }).catch((err) => { console.log('[WechatShare] Web Share 取消或失败:', err); }); } else { // 复制链接到剪贴板 const link = shareConfigRef.current.link || window.location.href; navigator.clipboard?.writeText(link).then(() => { console.log('[WechatShare] 链接已复制'); }); } return { type: 'web', success: true }; } // 微信环境:无法直接触发分享,返回提示信息 return { type: 'wechat', success: true, message: '请点击右上角「...」进行分享', }; }, [isInWechat]); /** * 手动更新分享配置 */ const setShareConfig = useCallback((newConfig) => { shareConfigRef.current = { ...shareConfigRef.current, ...newConfig, }; if (isReady && isInWechat) { updateShareData(); } }, [isReady, isInWechat, updateShareData]); return { isReady, // JS-SDK 是否就绪 isInWechat, // 是否在微信浏览器中 isLoading, // 是否正在加载 error, // 错误信息 triggerShare, // 触发分享引导 setShareConfig, // 手动更新分享配置 updateShareData, // 手动更新分享数据到微信 }; }; export default useWechatShare;