/www/wwwroot/www.9ywk.com/usr/plugins/AMP/templates/MIPpage.php on line 31
">

H5微信分享卡片

2025-11-16T20:36:00


在微信生态中,分享链接到朋友圈或朋友,发现分享出去是一串链接,没有卡片样式,查看微信文档,需要微信JS-SDK进行配置与调用,而且还需要公众号(企业认证类)才行。那么个人开发者如何使用呢,这里我们可以走曲线,微信测试号来实现。

[scode type="blue" size=""]需要工信部备案域名,注册一个测试号[/scode]
测试号签名生成接口请求有限,单独写个工具,需要分享进工具填写参数再分享。

登录微信测试号,设置安全域名,记住appid和密钥。

生成请求接口

wx_sign.php

<?php
// ================================
// 微信分享签名生成接口
// ================================
// ==== 1. 替换为你自己的公众号信息 ====
// (在微信公众平台 → 开发 → 基本配置 中查看)
$appid = "XXXXXX";
$appsecret = "XXXXXXXXXXXXXXX";

// ==== 2. 获取 access_token ====
$token_data = json_decode(file_get_contents("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$appsecret"), true);
if (!isset($token_data['access_token'])) {
    echo json_encode(['error' => '无法获取access_token']);
    exit;
}
$access_token = $token_data['access_token'];

// ==== 3. 获取 jsapi_ticket ====
$ticket_data = json_decode(file_get_contents("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$access_token&type=jsapi"), true);
if (!isset($ticket_data['ticket'])) {
    echo json_encode(['error' => '无法获取jsapi_ticket']);
    exit;
}
$jsapi_ticket = $ticket_data['ticket'];

// ==== 4. 生成签名 ====
$nonceStr = "9ywkcom" . rand(1000,9999);
$timestamp = time();
$url = $_GET['url'] ?? '';

$string = "jsapi_ticket=$jsapi_ticket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
$signature = sha1($string);

// ==== 5. 返回JSON ====
echo json_encode([
    "appId" => $appid,
    "timestamp" => $timestamp,
    "nonceStr" => $nonceStr,
    "signature" => $signature
]);
?>

[scode type="blue" size="simple"]
访问wx_sign.php返回类似
{"appId":"xxxxxx","timestamp":1763294755,"nonceStr":"xxx","signature":"xxxxx"}说明配置成功
[/scode]

Index

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>微信分享参数设置工具</title>
  <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
  <style>
    body {
      font-family: "Segoe UI", "Microsoft YaHei", sans-serif;
      background: #f8f9fb;
      padding: 16px;
      color: #333;
      font-size: 14px;
    }
    h2 {
      text-align: center;
      margin-bottom: 15px;
      font-size: 18px;
    }
    .config-box {
      max-width: 420px;
      margin: 0 auto;
      background: #fff;
      border-radius: 10px;
      box-shadow: 0 2px 6px rgba(0,0,0,0.1);
      padding: 14px;
    }
    label {
      display: block;
      margin: 8px 0 3px;
      font-weight: bold;
      font-size: 13px;
    }
    input {
      width: 100%;
      padding: 5px 8px;
      border-radius: 6px;
      border: 1px solid #ccc;
      font-size: 13px;
    }
    .btn {
      margin-top: 10px;
      width: 30%;
      display: inline-block;
      background: #409eff;
      color: #fff;
      padding: 7px 0;
      border: none;
      border-radius: 6px;
      font-size: 13px;
      cursor: pointer;
      transition: 0.2s;
    }
    .btn:hover {
      background: #66b1ff;
    }
    .btn-secondary {
      background: #999;
    }
    .btn-secondary:hover {
      background: #aaa;
    }
    .btn-refresh {
      background: #67c23a;
    }
    .btn-refresh:hover {
      background: #85ce61;
    }
    p.notice {
      text-align: center;
      margin-top: 6px;
      color: #666;
      font-size: 12px;
    }

    /* ====== 预览区域样式 ====== */
    .preview-area {
      max-width: 340px;
      margin: 20px auto 0;
    }
    .preview-title {
      font-weight: bold;
      font-size: 13px;
      margin: 8px 0 4px;
      color: #444;
      text-align: left;
    }
    .preview-card {
      background: #fff;
      border-radius: 8px;
      box-shadow: 0 1px 3px rgba(0,0,0,0.1);
      margin-bottom: 12px;
      overflow: hidden;
      padding: 6px;
    }
    /* 朋友圈预览 */
    .preview-timeline {
      display: flex;
      align-items: center;
      gap: 6px;
    }
    .preview-timeline img {
      width: 45px;
      height: 45px;
      border-radius: 6px;
      object-fit: cover;
      flex-shrink: 0;
    }
    .preview-timeline .title {
      font-size: 12.5px;
      font-weight: bold;
      color: #333;
      flex: 1;
      line-height: 1.3;
      word-break: break-word;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    /* 分享给朋友预览 */
    .preview-appmsg {
      padding: 4px;
    }
    .preview-appmsg .title {
      font-size: 12.5px;
      font-weight: bold;
      margin-bottom: 2px;
      color: #333;
      line-height: 1.3;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    .preview-appmsg .desc-row {
      display: flex;
      align-items: flex-start;
      gap: 5px;
    }
    .preview-appmsg .desc {
      flex: 1;
      font-size: 12px;
      color: #666;
      line-height: 1.3;
      max-height: 30px;
      overflow: hidden;
      text-overflow: ellipsis;
      word-break: break-word;
    }
    .preview-appmsg img {
      width: 40px;
      height: 40px;
      border-radius: 6px;
      object-fit: cover;
      flex-shrink: 0;
    }
  </style>
</head>
<body>
  <h2>微信分享设置工具</h2>
  <div class="config-box">
    <label>分享标题(最多66字符):</label>
    <input type="text" id="title" maxlength="66" placeholder="例如:玖月博客 | www.9ywk.com" oninput="limitTitleLength(); updatePreview();">

    <label>分享描述(最多120字符):</label>
    <input type="text" id="desc" maxlength="120" placeholder="例如:摘要描述..." oninput="limitDescLength(); updatePreview();">

    <label>分享链接:</label>
    <input type="text" id="link" placeholder="例如:https://www.9ywk.com" oninput="updatePreview()">

    <label>缩略图URL:</label>
    <input type="text" id="imgUrl" placeholder="SSL-URL" oninput="updatePreview()">

    <div style="text-align:center;display:flex;justify-content:space-between;gap:5px;flex-wrap:wrap;">
      <button class="btn" onclick="saveConfig()">保存</button>
      <button class="btn btn-refresh" onclick="refreshPage()">刷新</button>
      <button class="btn btn-secondary" onclick="resetConfig()">重置</button>
    </div>
    <p class="notice">保存后刷新页面即可生效</p>
  </div>

  <!-- ======= 预览区 ======= -->
  <div class="preview-area">
    <div class="preview-title">分享朋友圈预览</div>
    <div class="preview-card">
      <div class="preview-timeline">
        <img id="previewTimelineImg" src="" alt="缩略图">
        <div class="title" id="previewTimelineTitle"></div>
      </div>
    </div>

    <div class="preview-title">分享给朋友预览</div>
    <div class="preview-card">
      <div class="preview-appmsg">
        <div class="title" id="previewAppmsgTitle"></div>
        <div class="desc-row">
          <div class="desc" id="previewAppmsgDesc"></div>
          <img id="previewAppmsgImg" src="" alt="缩略图">
        </div>
      </div>
    </div>
  </div>

  <script>
    const defaultConfig = {
      title: '玖月博客 | www.9ywk.com',
      desc: '摘要描述...',
      link: 'https://www.9ywk.com',
      imgUrl: 'https://cdn.9ywk.com/2025/11/96ecb8d4f841c.png'
    };

    const saved = JSON.parse(localStorage.getItem('wxShareConfig') || '{}');
    const current = Object.assign({}, defaultConfig, saved);

    document.getElementById('title').value = current.title;
    document.getElementById('desc').value = current.desc;
    document.getElementById('link').value = current.link;
    document.getElementById('imgUrl').value = current.imgUrl;

    function limitTitleLength() {
      const titleInput = document.getElementById('title');
      if (titleInput.value.length > 66) {
        titleInput.value = titleInput.value.slice(0, 66);
      }
    }

    function limitDescLength() {
      const descInput = document.getElementById('desc');
      if (descInput.value.length > 120) {
        descInput.value = descInput.value.slice(0, 120);
      }
    }

    function updatePreview() {
      const title = document.getElementById('title').value.trim() || defaultConfig.title;
      const desc = document.getElementById('desc').value.trim() || defaultConfig.desc;
      const imgUrl = document.getElementById('imgUrl').value.trim() || defaultConfig.imgUrl;

      document.getElementById('previewTimelineTitle').textContent = title;
      document.getElementById('previewTimelineImg').src = imgUrl;

      document.getElementById('previewAppmsgTitle').textContent = title;
      document.getElementById('previewAppmsgDesc').textContent = desc;
      document.getElementById('previewAppmsgImg').src = imgUrl;
    }

    updatePreview();

    function saveConfig() {
      const config = {
        title: document.getElementById('title').value.trim(),
        desc: document.getElementById('desc').value.trim(),
        link: document.getElementById('link').value.trim(),
        imgUrl: document.getElementById('imgUrl').value.trim()
      };
      localStorage.setItem('wxShareConfig', JSON.stringify(config));
      alert('保存成功!刷新后生效');
    }

    function refreshPage() {
      location.reload();
    }

    function resetConfig() {
      localStorage.removeItem('wxShareConfig');
      location.reload();
    }

    fetch('https://www.9ywk.com/wxtool/wx_sign.php?url=' + encodeURIComponent(location.href.split('#')[0]))
      .then(res => res.json())
      .then(config => {
        if (config.error) {
          console.error("签名接口错误:", config.error);
          return;
        }

        wx.config({
          debug: false,
          appId: config.appId,
          timestamp: config.timestamp,
          nonceStr: config.nonceStr,
          signature: config.signature,
          jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage']
        });

        wx.ready(function () {
          const share = JSON.parse(localStorage.getItem('wxShareConfig') || '{}');
          const params = Object.assign({}, defaultConfig, share);

          wx.onMenuShareTimeline({
            title: params.title,
            link: params.link,
            imgUrl: params.imgUrl
          });

          wx.onMenuShareAppMessage({
            title: params.title,
            desc: params.desc,
            link: params.link,
            imgUrl: params.imgUrl
          });
        });

        wx.error(function (err) {
          console.error('微信配置错误:', err);
        });
      });
  </script>
</body>
</html>

当前页面是本站的「Baidu MIP」版。发表评论请点击:完整版 »