Vue3+TS的H5项目实现微信分享卡片样式

需求背景

由于项目是H5的,用户主要是通过微信扫码进入,在微信上操作,并且会有分享操作,这里不做处理的话,另一方收到的就是一段链接而已,不好看,所以想实现卡片式的分享。最终想要实现的效果如下:

技术栈

  • vue:3.5.13
  • weixin-js-sdk-ts:1.6.1

实现步骤

安装weixin-js-sdk-ts

npm install [email protected]

sdk初始化

查阅微信网页开发 / JS-SDK说明文档,内部提到:

于是我封装了初始化微信的 hooks,在页面初始化的时候调用并传递当前页面 url调用后端接口来获取微信初始化所需要的参数:

ts 复制代码
import wx from "weixin-js-sdk-ts";
import LiveApi from "@/apis/live/index";

/**
 * 微信 SDK 初始化钩子
 * @author 鹏北海 <[email protected]>
 * @since 2025-05-27
 *
 * @returns {{
 *   initWechat: (platform_url: string) => Promise<boolean>,
 *   wx: typeof wx
 * }} 返回包含以下成员的对象:
 *   - initWechat: 异步初始化微信 SDK 配置的方法
 *   - wx: 微信 JS-SDK 实例
 *
 * @remarks
 * 实现细节:
 * - 通过 `LiveApi.getWeChatKey` 获取签名配置
 * - 开发环境开启调试模式(根据 import.meta.env.MODE 判断)
 * - 初始化配置包含分享功能所需的 `updateAppMessageShareData` API
 * - 使用 Promise 包装微信 SDK 的 ready/error 回调机制
 *
 * @example
 * const { initWechat, wx } = useWechat();
 * await initWechat('https://example.com');
 *
 * @see {@link https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html} weixin-js-sdk 说明文档
 */
export function useWechat() {
  const initWechat = async (platform_url: string) => {
    const { data } = await LiveApi.getWeChatKey(platform_url);
    console.log("%c初始化微信SDK配置", "color: green;");
    const config: WeixinConfig = {
      debug: /* import.meta.env.MODE === "development" */ false, // 开发环境开启调试
      appId: data.appId,
      timestamp: data.timestamp,
      nonceStr: data.nonceStr,
      signature: data.signature,
      jsApiList: ["updateAppMessageShareData", "updateTimelineShareData"], // 我需要用到这两个api
      openTagList: [],
    };
    wx.config(config);
    return new Promise((resolve, reject) => {
      wx.ready(() => {
        console.log("%cwx.ready", "color: green;");
        resolve(true);
      });
      wx.error((error) => {
        console.log("%cwx.error", "color: red;");
        reject(error);
      });
    });
  };

  return { initWechat, wx };
}

使用方法:

ts 复制代码
<script setup lang="ts">
import { useWechat } from "@/hooks/useWechat";

await initWechat(window.location.href);

wx.updateAppMessageShareData({...})
wx.updateTimelineShareData({...})
</script>

响应式配置分享参数

因为实际业务中,调用分享 api 的参数是异步获取的,,所以我又在初始化的基础上封装了一个微信分享的 hooks,以保证微信分享时,能够获得异步获取到的数据来配置参数:

ts 复制代码
import { watch } from "vue";
import { useWechat } from "./useWechat";

/**
 * 微信分享自定义钩子
 * @author 鹏北海 <[email protected]>
 * @since 2025-05-27
 *
 * @param {Object} options - 配置选项
 * @param {Function} options.trigger - 触发分享配置更新的观察函数(当返回值变化时触发更新)
 * @param {string|function} options.title - 分享标题(支持响应式函数)
 * @param {string|function} options.desc - 分享描述(支持响应式函数)
 * @param {string|function} [options.imgUrl] - 分享图标URL(支持响应式函数,可选)
 * @param {string|function} [options.link] - 微信初始化路径(支持响应式函数)
 * @param {Function} [options.onSuccess] - 分享配置成功回调(可选)
 * @param {Function} [options.onError] - 分享配置失败/取消回调(可选)
 * @returns {{
 *   startWxShareWatch: () => void
 * }} 返回包含以下方法的对象:
 
 * @remarks
 * 该钩子使用 Vue 的 `watch` 实现响应式配置更新,通过设置 flush: 'post' 确保
 * 在 DOM 更新后执行分享配置。使用前需确保已正确加载微信 JS-SDK。
 *
 * 注意,分享标题、描述、图标url可以是响应式函数,如果这些数据是异步返回的,
 * 请使用响应式函数的形式,保证 hooks 能读取到有效数据
 * 并且传递 trigger 函数来触发分享配置更新。否则直接传递字符串形式,并且不用传递 trigger 函数。
 *
 * @see {@link https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#10} 微信分享
 */
 
 export function useWechatShare(options: {
  trigger?: () => unknown;
  title: (() => string) | string;
  desc?: (() => string) | string;
  imgUrl?: (() => string) | string;
  link: (() => string) | string;
  onSuccess?: () => void;
  onError?: () => void;
}) {
  const { wx, initWechat } = useWechat();
  // 如果没有提供描述,则使用默认值
  if (!options.desc) {
    console.log(
      "缺少描述,使用默认值: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。",
    );
    options.desc =
      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx。";
  }
  const startWxShareWatch = async () => {
    if (!options.trigger) {
      await fun();
    } else {
      const stop = watch(
        options.trigger,
        async (_newValue, _oldValue) => {
          await fun(stop);
        },
        {
          // 确保在 DOM 更新后执行,避免获取过时的页面 URL
          flush: "post",
        },
      );
    }

    async function fun(stop?: () => void) {
      try {
        await initWechat(window.location.href);
        console.log("initWechat");
        const success = (msg: string) => {
          return () => {
            console.log(`${msg}分享配置更新成功`);
            options.onSuccess?.();
            stop?.(); // 配置成功后停止监听
          };
        };

        const cancel = (msg: string) => {
          return () => {
            console.log(`${msg}分享配置更新取消`);
            options.onError?.();
          };
        };
        console.log("=============  options =============");
        console.log(options);

        wx.updateAppMessageShareData({
          title: typeof options.title === "function" ? options.title() : options.title,
          desc: typeof options.desc === "function" ? options.desc() : options.desc!,
          link: typeof options.link === "function" ? options.link() : options.link,
          imgUrl: options.imgUrl ? (typeof options.imgUrl === "function" ? options.imgUrl() : options.imgUrl) : "",
          success: success("QQ、微信"),
          cancel: cancel("QQ、微信"),
        });
        wx.updateTimelineShareData({
          title: typeof options.title === "function" ? options.title() : options.title,
          link: options.link ? (typeof options.link === "function" ? options.link() : options.link) : "",
          imgUrl: options.imgUrl ? (typeof options.imgUrl === "function" ? options.imgUrl() : options.imgUrl) : "",
          success: success("朋友圈、QQ空间"),
          cancel: cancel("朋友圈、QQ空间"),
        });
      } catch (error) {
        console.error("微信初始化失败", error);
        options.onError?.();
      }
    }
  };

  return {
    startWxShareWatch,
  };
}

使用方式,在每一个需要分享的页面:

ts 复制代码
<script setup lang="ts">
import { useWechatShare } from "@/hooks/useWechatShare";
import { onMounted } from "vue";

// 初始化微信分享
const { startWxShareWatch } = useWechatShare({
  title: () => "标题",
  imgUrl: () => "图片url",
  desc: "描述",
  link: window.location.href, // 分享当前页面
});

// 监听微信分享状态变化
startWxShareWatch();
</script>

而如果分享所需要的数据是接口异步返回的:

ts 复制代码
<script setup lang="ts">
import { useWechatShare } from "@/hooks/useWechatShare";

const liveReactiveData = reactive({
    livePoster: "",
    liveTitle: "",
    liveDesc: ""
})

// 初始化微信分享
const { startWxShareWatch } = useWechatShare({
  trigger: () => liveReactiveData.liveTitle,
  title: () => liveReactiveData.liveTitle,
  desc: () => liveReactiveData.liveDesc
  imgUrl: () => liveReactiveData.livePoster,
  link: window.location.href
});

  


// 监听微信分享状态变化
startWxShareWatch();

onMounted(() => {
    // 模拟异步获取数据
    setTimeout(() => {
        liveReactiveData.liveTitle = "标题";
        liveReactiveData.livePoster = "https://xxxxxxxxx.png";
        liveReactiveData.liveDesc = "描述";
    }, 5000)
})
</script>

大功告成!!!

相关推荐
喵手5 分钟前
CSS3 渐变、阴影和遮罩的使用
前端·css·css3
顽强d石头6 分钟前
bug:undefined is not iterable (cannot read property Symbol(Symbol.iterator))
前端·bug
烛阴16 分钟前
模块/命名空间/全局类型如何共存?TS声明空间终极生存指南
前端·javascript·typescript
火车叼位19 分钟前
Git 精准移植代码:cherry-pick 简单说明
前端·git
江城开朗的豌豆23 分钟前
JavaScript篇:移动端点击的300ms魔咒:你以为用户手抖?其实是浏览器在搞事情!
前端·javascript·面试
华洛30 分钟前
聊聊我们公司的AI应用工程师每天都干啥?
前端·javascript·vue.js
江城开朗的豌豆30 分钟前
JavaScript篇:你以为事件循环都一样?浏览器和Node的差别让我栽了跟头!
前端·javascript·面试
gyx_这个杀手不太冷静33 分钟前
Vue3 响应式系统探秘:watch 如何成为你的数据侦探
前端·vue.js·架构
晴殇i39 分钟前
🌐 CDN跨域原理深度解析:浏览器安全策略的智慧设计
前端·面试·程序员
Uyker1 小时前
空间利用率提升90%!小程序侧边导航设计与高级交互实现
前端·微信小程序·小程序