Files
vf_react/src/hooks/useWechatShare.js
2025-12-28 22:53:40 +08:00

233 lines
6.7 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.

// 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;