导读:本期聚焦于闲进程创作的《微信公众号自定义菜单点击后如何弹出卡券列表并让用户选择卡券?》,敬请观看详情。微信公众号菜单点击后直接弹出卡券列表,并不是普通click事件能够独立完成的。卡券选择器属于微信JS-SDK的前端能力,必须在已经配置好JS接口安全域名的网页里调用。实现时通常先让自定义菜单跳转到活动页面,页面加载后调用chooseCard接口,微信会向用户展示指定公众号下可用的卡券列表,用户选择后返回cardId和code。服务端需要提前获取jsapi_ticket并生成有效签名,同时保证卡券已经通过微信卡券接口创建成功。前端拿到选择结果后,可以交给服务端进行核销、绑定或写入数据库。整个过程涉及菜单配置、access_token管理、JS-SDK签名、卡券选择回调与结果处理几个环节。注意菜单类型建议使用view直接打开网页,click事件更适合回复消息或记录点击行为。卡券类型不同,chooseCard参数和返回结构也会略有差异。

微信公众号自定义菜单本身支持click和view等类型,但点击菜单直接弹出卡券列表并不属于click事件的服务端推送能力。卡券选择器由微信JS-SDK提供,它是一个运行在网页中的前端接口,只有先进入一个已绑定JS接口安全域名的页面,才能调用window.wx.chooseCard方法拉取卡券列表。因此,想要实现菜单点击后弹出卡券选择器,最直接的方式是把菜单配置为view类型并指向活动页面,用户在进入页面后由前端代码发起卡券选择请求。

微信公众号自定义菜单点击后如何弹出卡券列表并让用户选择卡券?

整个功能可以拆分为四个部分:配置自定义菜单和JS安全域名、服务端生成JS-SDK签名、前端调用chooseCard接口、服务端接收并处理用户选择的卡券。每一步都有容易出错的细节,尤其是签名生成和卡券类型参数,下面分别展开说明。

整体实现流程与前置条件

用户点击菜单后的完整链路是:微信客户端触发菜单跳转,打开活动页;活动页加载时从服务端获取appId、timestamp、nonceStr和signature等配置;页面初始化wx.config并调用wx.ready;在ready回调中执行wx.chooseCard弹出卡券列表;用户选择后前端拿到的cardId和code回传到服务端进行核销或存储。

开始开发之前,首先要确认公众号类型。只有认证服务号才具备卡券功能权限和JS-SDK调用权限,未认证的订阅号无法使用卡券选择器。其次要在微信公众平台后台配置JS接口安全域名,域名必须通过ICP备案,并且配置成页面实际使用的完整域名,不能带端口。同时,如果活动页需要获取用户身份,还要配置网页授权域名。

自定义菜单建议直接使用view类型,因为view类型可以跳转到指定URL,避免用户在click事件后再手动点击图文消息进入网页。菜单的view按钮URL会经过OAuth2.0网页授权或直接拼接参数,保证页面能拿到足够信息。卡券本身需要提前通过微信卡券API创建,无论是代金券、折扣券、兑换券还是优惠券,都必须先有cardId,否则chooseCard会因为没有可用卡券而返回空列表。

服务端生成JS-SDK签名

JS-SDK的签名算法并不复杂,但关键在于jsapi_ticket的获取和缓存。jsapi_ticket的有效期为7200秒,服务端不能每次请求都重新获取,否则会触发微信接口频率限制。通常的做法是使用Redis或文件缓存保存ticket,过期后再重新拉取。access_token也是同样的处理逻辑,有效期同为7200秒。

签名字符串由jsapi_ticket、noncestr、timestamp和当前页面完整URL拼接而成,顺序固定为jsapi_ticket、noncestr、timestamp、url,中间用&符号连接,然后做SHA1哈希。需要注意URL必须去掉#号及之后的内容,但保留全部查询参数,并且必须与前端实际调用时的地址完全一致,否则签名校验会失败。

<?php
function getAccessToken($appid, $secret) {
    $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $appid . '&secret=' . $secret;
    $data = json_decode(file_get_contents($url), true);
    return isset($data['access_token']) ? $data['access_token'] : '';
}

function getJsApiTicket($accessToken) {
    $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $accessToken . '&type=jsapi';
    $data = json_decode(file_get_contents($url), true);
    return isset($data['ticket']) ? $data['ticket'] : '';
}

function buildSignature($ticket, $noncestr, $timestamp, $url) {
    $str = 'jsapi_ticket=' . $ticket . '&noncestr=' . $noncestr . '&timestamp=' . $timestamp . '&url=' . $url;
    return sha1($str);
}
?>

生成签名后,服务端需要把这些值通过接口返回给前端。签名中的noncestr可以随机生成,timestamp使用当前秒级时间戳。如果页面采用前后端分离方式,建议单独提供一个签名接口,前端在wx.config之前异步获取签名数据,避免将access_token或jsapi_ticket暴露在页面源代码中。

前端调用chooseCard选择卡券

前端页面要先引入微信JS-SDK文件,然后在页面初始化时执行wx.config。config中的jsApiList必须包含chooseCard,否则后续调用会被拒绝。debug参数在测试环境可以设置为true,方便查看签名校验结果,但上线前要关闭。

wx.ready是一个回调函数,表示JS-SDK认证完成,之后才能安全调用chooseCard。chooseCard方法接收一个对象参数,其中cardId可以是单个卡券ID,也可以传空字符串表示拉取该公众号下所有可用卡券。cardType用于限定卡券类型,常见的有GROUPON、CASH、DISCOUNT、GIFT、MEMBER_CARD等。如果活动只允许用户选择某一种券,就同时传入cardId和cardType;如果希望用户自行选择任意卡券,cardId可以置空,cardType仍然建议传入,否则列表可能混入会员卡等不需要的类型。

wx.config({
    debug: false,
    appId: '<?php echo $appId; ?>',
    timestamp: '<?php echo $timestamp; ?>',
    nonceStr: '<?php echo $noncestr; ?>',
    signature: '<?php echo $signature; ?>',
    jsApiList: ['chooseCard']
});

wx.ready(function () {
    wx.chooseCard({
        cardId: '',
        cardType: 'GROUPON',
        success: function (res) {
            var cardList = res.cardList;
            if (cardList.length === 0) {
                alert('未选择任何卡券');
                return;
            }
            var cardId = cardList[0].cardId;
            var code = cardList[0].code;
            var xhr = new XMLHttpRequest();
            xhr.open('POST', '/consume.php', true);
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send('cardId=' + encodeURIComponent(cardId) + '&code=' + encodeURIComponent(code));
        },
        cancel: function () {
            console.log('用户取消了卡券选择');
        },
        fail: function (err) {
            console.error('卡券选择失败', err);
        }
    });
});

success回调中的cardList是一个数组,每个元素包含cardId、code等字段。对于会员卡,可能还包含membershipNumber等信息。用户取消选择时会触发cancel回调,这与fail不同,fail通常表示调用参数错误、签名失败或JS接口未授权。前端拿到cardId和code后,一定要通过HTTPS接口回传给服务端,避免在浏览器端直接进行核销操作。

服务端接收选择结果并核销卡券

当用户选择卡券后,cardId和code会提交到服务端。服务端需要先校验这两个参数的合法性,避免恶意请求。卡券code在核销前可以通过微信卡券查询接口获取卡券状态,确认卡券是否已被核销、是否在有效期内、是否属于当前公众号。这一步能有效防止重复核销和无效请求。

确认卡券可用后,服务端调用核销接口消耗卡券。核销接口需要access_token、card_id和code,请求方式为POST,JSON格式。核销成功后微信会返回当前用户的openid,可以用来绑定用户与卡券关系。核销操作具有业务影响,应该放在数据库事务或消息队列中与本地业务逻辑联动,避免网络超时造成状态不一致。

<?php
function consumeCard($accessToken, $cardId, $code) {
    $url = 'https://api.weixin.qq.com/card/code/consume?access_token=' . $accessToken;
    $data = array(
        'card_id' => $cardId,
        'code' => $code
    );
    $json = json_encode($data);
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return json_decode($result, true);
}
?>

核销成功后不能简单给用户返回一个普通文本,最好跳转到一个结果页或展示卡券核销状态。如果卡券是折扣券,可以同时把用户选择的优惠信息写入订单系统。对于不需要核销的场景,例如会员卡或礼品券,也可能只需要存储用户选择的卡券信息,服务端根据业务需求进行处理即可。

常见问题与调试建议

签名错误是最常见的问题。如果wx.config提示invalid signature,先检查前端页面URL是否与签名URL完全一致,包括协议、域名、路径和查询参数。微信内置浏览器对URL规范化要求较高,带尾部斜杠或不带都可能导致不一致。建议在服务端签名接口里输出当前URL,用于对照前端实际地址。

另一个常见问题是卡券列表为空。除了确认卡券已经创建并审核通过外,还要检查chooseCard的参数是否限制了cardId或cardType。如果接口返回错误码,需要查看微信公众平台开发者文档,根据具体错误调整参数。调试时可以在wx.config中打开debug模式,微信会弹出详细的错误信息,帮助定位问题。

菜单点击事件本身不会直接弹出卡券列表,所以不要把精力放在click事件的XML处理上。click事件只能告诉服务端用户点击了哪个菜单,适合记录用户行为或回复消息,但无法唤起前端JS-SDK接口。只要理解了这一点,整个开发思路就会更加清晰。

微信公众号卡券自定义菜单事件JS-SDK卡券选择修改时间:2026-08-21 15:36:13

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。