https://developers.weixin.qq.com/doc/service/guide/h5/ 无法支持图文卡片式分享给朋友和朋友圈:
wechatshare hook代码:
import { useEffect, useState, useRef } from 'react';
declare global {
interface Window {
wx: any;
}
}
interface WechatShareConfig {
title: string;
desc: string;
link: string;
imgUrl: string;
success?: () => void;
cancel?: () => void;
fail?: (error: any) => void;
// 新增:分享类型相关的回调
onFriendsShareSuccess?: () => void;
onTimelineShareSuccess?: () => void;
onFriendsShareCancel?: () => void;
onTimelineShareCancel?: () => void;
onFriendsShareFail?: (error: any) => void;
onTimelineShareFail?: (error: any) => void;
}
interface WechatSignature {
appId: string;
timestamp: number;
nonceStr: string;
signature: string;
}
export default function useWechatShare() {
const [isWechatReady, setIsWechatReady] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isInitialized, setIsInitialized] = useState(false); // 新增:标记是否已初始化
const initPromiseRef = useRef<Promise<boolean> | null>(null); // 新增:保存初始化Promise
// 检测是否在微信浏览器中
const isWechatBrowser = () => {
if (typeof window === 'undefined') return false;
const ua = window.navigator.userAgent.toLowerCase();
return ua.includes('micromessenger');
};
// 加载微信JS-SDK
const loadWechatSDK = () => {
return new Promise((resolve, reject) => {
if (window.wx) {
resolve(window.wx);
return;
}
const script = document.createElement('script');
script.src = 'https://res.wx.qq.com/open/js/jweixin-1.6.0.js';
script.onload = () => resolve(window.wx);
script.onerror = reject;
document.head.appendChild(script);
});
};
// 获取微信签名
const getWechatSignature = async (url: string): Promise<WechatSignature> => {
const response = await fetch(`/api/wechat/signature?url=${encodeURIComponent(url)}`);
if (!response.ok) {
throw new Error('获取微信签名失败');
}
return response.json();
};
// 初始化微信JS-SDK
const initWechatSDK = async () => {
if (!isWechatBrowser()) {
console.log('非微信浏览器环境');
return false;
}
// 如果已经在初始化中,返回现有的Promise
if (initPromiseRef.current) {
console.log('SDK正在初始化中,等待完成...');
return initPromiseRef.current;
}
// 如果已经初始化完成,直接返回结果
if (isInitialized) {
console.log('SDK已初始化,当前状态:', isWechatReady);
return isWechatReady;
}
// 创建新的初始化Promise
initPromiseRef.current = (async () => {
try {
setIsLoading(true);
console.log('开始初始化微信SDK...');
// 加载微信SDK
await loadWechatSDK();
// 获取当前页面URL(去掉hash部分)
const currentUrl = window.location.href.split('#')[0];
// 获取签名
const signature = await getWechatSignature(currentUrl);
// 配置微信SDK
window.wx.config({
debug: process.env.NODE_ENV === 'development', // 开发环境自动开启调试
appId: signature.appId,
timestamp: signature.timestamp,
nonceStr: signature.nonceStr,
signature: signature.signature,
jsApiList: [
'updateAppMessageShareData', // 分享给朋友
'updateTimelineShareData' // 分享到朋友圈
]
});
// 配置成功回调
return new Promise<boolean>((resolve) => {
window.wx.ready(() => {
console.log(`${new Date().toString()} wx.config ready`);
console.log('微信JS-SDK配置成功');
setIsWechatReady(true);
setIsInitialized(true);
resolve(true);
});
// 配置失败回调
window.wx.error((res: any) => {
console.error(`${new Date().toString()} wx.config error:`, res);
console.error('微信JS-SDK配置失败:', res);
// 更详细的错误信息
if (res.errMsg) {
console.error('错误详情:', res.errMsg);
if (typeof window !== 'undefined' && window.console) {
console.warn('微信分享功能暂时不可用,请确保在微信浏览器中打开');
}
}
setIsWechatReady(false);
setIsInitialized(true); // 即使失败也标记为已初始化,避免重复尝试
resolve(false);
});
});
} catch (error) {
console.error('初始化微信SDK失败:', error);
setIsWechatReady(false);
setIsInitialized(true); // 标记为已初始化,避免重复尝试
return false;
} finally {
setIsLoading(false);
initPromiseRef.current = null; // 清除Promise引用
}
})();
return initPromiseRef.current;
};
// 配置分享内容
const configShare = (config: WechatShareConfig) => {
if (!isWechatReady || !window.wx) {
console.warn('微信SDK未准备就绪,当前状态:', { isWechatReady, hasWx: !!window.wx });
return false;
}
try {
console.log('配置微信分享内容:', config.title);
// 确保图片URL是绝对路径
const getAbsoluteImageUrl = (imageUrl: string) => {
if (!imageUrl) return '';
if (imageUrl.startsWith('http')) return imageUrl;
return `${window.location.origin}${imageUrl.startsWith('/') ? '' : '/'}${imageUrl}`;
};
const absoluteImgUrl = getAbsoluteImageUrl(config.imgUrl);
// 检查当前客户端版本是否支持分享接口
window.wx.checkJsApi({
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData'],
success: function(res: any) {
console.log('分享接口支持情况:', res.checkResult);
if (!res.checkResult.updateAppMessageShareData) {
console.warn('当前微信版本不支持updateAppMessageShareData接口');
}
if (!res.checkResult.updateTimelineShareData) {
console.warn('当前微信版本不支持updateTimelineShareData接口');
}
}
});
// 配置分享给朋友
console.log(`${new Date().toString()} wx.updateAppMessageShareData begin`);
console.log({
title: config.title,
desc: config.desc,
link: config.link,
imgUrl: absoluteImgUrl
});
window.wx.updateAppMessageShareData({
title: config.title,
desc: config.desc,
link: config.link,
imgUrl: absoluteImgUrl,
success: () => {
console.log(`${new Date().toString()} wx.updateAppMessageShareData success - 配置成功`);
// 这个success回调表示配置成功,不是分享成功
// 可以统计为"分享配置成功"或"分享意图"
config.onFriendsShareSuccess?.();
config.success?.(); // 保持向后兼容
},
cancel: () => {
console.log('取消分享给朋友');
config.onFriendsShareCancel?.();
config.cancel?.(); // 保持向后兼容
},
fail: (error: any) => {
console.error('分享给朋友失败:', error);
config.onFriendsShareFail?.(error);
config.fail?.(error); // 保持向后兼容
}
});
console.log(`${new Date().toString()} wx.updateAppMessageShareData end`);
// 配置分享到朋友圈
console.log(`${new Date().toString()} wx.updateTimelineShareData begin`);
console.log({
title: config.title,
link: config.link,
imgUrl: absoluteImgUrl
});
window.wx.updateTimelineShareData({
title: config.title,
link: config.link,
imgUrl: absoluteImgUrl,
success: () => {
console.log(`${new Date().toString()} wx.updateTimelineShareData success - 配置成功`);
// 这个success回调表示配置成功,不是分享成功
// 可以统计为"分享配置成功"或"分享意图"
config.onTimelineShareSuccess?.();
config.success?.(); // 保持向后兼容
},
cancel: () => {
console.log('取消分享到朋友圈');
config.onTimelineShareCancel?.();
config.cancel?.(); // 保持向后兼容
},
fail: (error: any) => {
console.error('分享到朋友圈失败:', error);
config.onTimelineShareFail?.(error);
config.fail?.(error); // 保持向后兼容
}
});
console.log(`${new Date().toString()} wx.updateTimelineShareData end`);
return true;
} catch (error) {
console.error('配置分享失败:', error);
config.fail?.(error);
return false;
}
};
// 一步配置分享(改进版)
const setupShare = async (config: WechatShareConfig) => {
console.log('setupShare调用,当前状态:', { isWechatReady, isInitialized, isLoading });
// 如果SDK已就绪,直接配置
if (isWechatReady) {
return configShare(config);
}
// 如果未初始化,先初始化
if (!isInitialized && !isLoading) {
const initialized = await initWechatSDK();
if (initialized) {
return configShare(config);
}
}
// 如果正在加载中,等待加载完成
if (isLoading && initPromiseRef.current) {
const initialized = await initPromiseRef.current;
if (initialized) {
return configShare(config);
}
}
console.warn('setupShare失败,SDK未能初始化成功');
return false;
};
// 页面加载时自动初始化(只初始化一次)
useEffect(() => {
if (isWechatBrowser() && !isInitialized && !isLoading) {
console.log('页面加载,自动初始化微信SDK');
initWechatSDK();
}
}, []); // 空依赖数组,只在组件挂载时执行一次
return {
isWechatBrowser: isWechatBrowser(),
isWechatReady,
isLoading,
isInitialized, // 新增:暴露初始化状态
initWechatSDK,
configShare,
setupShare
};
}
全页面的日志信息是如下,显示:
页面的日志信息是如下,显示
[id]-557c3938a7c7903c.js:1
更新作者资料:
{id: 24, created_at: "2025-05-07T19:45:48.475157+08:00", updated_at: "2025-07-17T18:14:58.808494+08:00", username: "sally 妈妈", email: "skynet2050@163.com", …}
[id]-557c3938a7c7903c.js:1
准备配置微信分享,当前状态:
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1
等待SDK自动初始化完成...
[id]-557c3938a7c7903c.js:1
Post data:
{id: 2324, created_at: "2025-06-22T13:05:03.456553+08:00", updated_at: "2025-07-16T21:03:44.87702+08:00", user_id: 24, user: {…}, …}
[id]-557c3938a7c7903c.js:1
User data in post:
{id: 24, created_at: "2025-05-07T19:45:48.475157+08:00", updated_at: "2025-07-17T18:14:58.808494+08:00", username: "sally 妈妈", email: "skynet2050@163.com", …}
[id]-557c3938a7c7903c.js:1
Display username: 赫尔弥斯
[id]-557c3938a7c7903c.js:1
Display avatar: https://image.inteducom.com/user_uploads/24/e257fe42-f966-453a-818a-df56c3acc9eb/edited-avatar.webp
_app-cafb680d520d278c.js:1
[useAuth checkAuth] Current login status: false
_app-cafb680d520d278c.js:1
[auth.ts] 正在设置Axios拦截器...
_app-cafb680d520d278c.js:1
[auth.ts] Axios拦截器设置完成
_app-cafb680d520d278c.js:1
[axios拦截器] 请求 GET /api/posts/2324/comments - 无token可用
_app-cafb680d520d278c.js:1
[axios拦截器] 响应成功: GET /api/posts/2324/comments - 状态 200
3
_app-cafb680d520d278c.js:1
[useAuth checkAuth] Current login status: false
[id]-557c3938a7c7903c.js:1
准备配置微信分享,当前状态:
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1
等待SDK自动初始化完成...
_app-cafb680d520d278c.js:1
[useAuth checkAuth] Current login status: false
[id]-557c3938a7c7903c.js:1
准备配置微信分享,当前状态:
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1
等待SDK自动初始化完成...
index.js:9
Fri Jul 18 2025 01:19:53 GMT+0800 (中国标准时间) wx.config begin
index.js:9
{appId: "wxd20e798f1bb60259", jsApiList: Array(2), nonceStr: "8h5gA6wHZAUM8g6V", signature: "0c40ca0cb9886d8a6032fda15f74da3bf27a2705", timestamp: "1752772794"}
[id]-557c3938a7c7903c.js:1
准备配置微信分享,当前状态:
{isWechatReady: false, isInitialized: false}
[id]-557c3938a7c7903c.js:1
等待SDK自动初始化完成...
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.config end
index.js:9
{errMsg: "config:ok", jsApiList: Array(2)}
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) 当前页面通过 wx.config 获取到的 JSSDK 权限如下
index.js:9
(index)
0
1
0 "updateAppMessageShareData" "updateTimelineShareData"
Array(1)
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.config ready
[id]-557c3938a7c7903c.js:1
微信JS-SDK配置成功
[id]-557c3938a7c7903c.js:1
准备配置微信分享,当前状态:
{isWechatReady: true, isInitialized: true}
[id]-557c3938a7c7903c.js:1
SDK已就绪,直接配置分享
[id]-557c3938a7c7903c.js:1
配置微信分享内容: 数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.checkJsApi begin
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData begin
[id]-557c3938a7c7903c.js:1
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", desc: "很多家长一听“建模竞赛”就头大,不知道是数学的建模,还是画图的建模。↵其实,“数学建模”和“3D建模…完全不同。↵这篇文章,帮你一文读懂两类建模的本质区别、适合人群及升学价值,帮助孩子选对适合自己的成", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData begin
index.js:9
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", desc: "很多家长一听“建模竞赛”就头大,不知道是数学的建模,还是画图的建模。↵其实,“数学建模”和“3D建模…完全不同。↵这篇文章,帮你一文读懂两类建模的本质区别、适合人群及升学价值,帮助孩子选对适合自己的成", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateAppMessageShareData end
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData begin
[id]-557c3938a7c7903c.js:1
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData begin
index.js:9
{title: "数学建模竞赛与3D建模竞赛全面对比解析 - IntEdu 国际社区", link: "https://www.inteducom.com/posts/2324", imgUrl: "https://image.inteducom.com/user_uploads/24/93894c8e-5f72-4e35-a685-451c4b45e5bf/1.webp"}
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData end
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.checkJsApi end
index.js:9
{errMsg: "checkJsApi:ok", checkResult: {…}}
[id]-557c3938a7c7903c.js:1
分享接口支持情况:
{updateAppMessageShareData: true, updateTimelineShareData: true}
index.js:9
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData end
index.js:9
{errMsg: "updateTimelineShareData:ok"}
[id]-557c3938a7c7903c.js:1
Fri Jul 18 2025 01:19:54 GMT+0800 (中国标准时间) wx.updateTimelineShareData success - 配置成功
[id]-557c3938a7c7903c.js:1
配置分享到朋友圈成功 - 这不是实际分享
[id]-557c3938a7c7903c.js:1
微信分享成功