介绍

微信、支付宝双收款码贴在摊位上占地方又不美观,这个方案把两个码合成一个:一张二维码扫开是一个 H5 落地页,页面按扫码者的 User-Agent 判断来源——微信扫码自动跳微信收款页,支付宝扫码自动跳支付宝收款页,浏览器扫码就弹一个支付方式选择按钮,全程不用二次扫码。思路来自吾爱破解论坛的这篇帖子,代码本身没有技术含量,核心就是 UA 判断加一个好看的过渡页,胜在实用。【摆摊、开店不收手续费的老办法里最顺手的方案,淘宝上卖几十块的"聚合收款码"商家版,原理也就是这个】

两个关键点要记住:微信那边不能用个人收款码,得先申请微信官方的【经营码】(其实就是商家收款码),申请下来后用二维码解码器把里面的 URL 解出来;支付宝这边简单,个人收款码就能用,同样解码出 URL。把两个 URL 分别替换进下面的源码里,部署到任意静态空间或服务器,生成一个二维码就完事了。

特征

🔍 按扫环境自动分流:微信、支付宝 App 内扫码直接跳各自支付页
🌐 浏览器扫码显示支付方式选择,不会打死路
📱 一个二维码搞定两套收款,摊位只贴一张码
⏱ 300ms 内自动跳转,过渡页有加载动画不显突兀
🎨 移动端卡片式 UI,圆角、阴影、图标齐全,观感干净
🔧 纯 HTML + 原生 JS,无依赖不放任何服务器框架,静态托管即可用

源码

以下为完整页面源码,把 PAY_URL 里的两个地址替换成你解码出来的收款 URL 即可直接使用:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 
    <title>收款</title>
 
    <style>
        * {
            box-sizing: border-box;
        }
 
        html,
        body {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            background: #f7f7f7;
            font-family:
                -apple-system,
                BlinkMacSystemFont,
                "Segoe UI",
                "PingFang SC",
                "Microsoft YaHei",
                Arial,
                sans-serif;
        }
 
        body {
            display: flex;
            align-items: center;
            justify-content: center;
        }
 
        .box {
            width: calc(100% - 40px);
            max-width: 420px;
            padding: 40px 25px;
            background: #fff;
            border-radius: 16px;
            text-align: center;
            box-shadow: 0 8px 30px rgba(0, 0, 0, .06);
        }
 
        .icon {
            width: 64px;
            height: 64px;
            margin: 0 auto 20px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #f1f1f1;
            font-size: 30px;
        }
 
        .title {
            font-size: 20px;
            font-weight: 600;
            color: #222;
            margin-bottom: 12px;
        }
 
        .desc {
            font-size: 14px;
            color: #999;
            line-height: 1.7;
        }
 
        .loading {
            width: 28px;
            height: 28px;
            margin: 22px auto 0;
            border: 3px solid #eee;
            border-top-color: #999;
            border-radius: 50%;
            animation: rotate .8s linear infinite;
        }
 
        @keyframes rotate {
            to {
                transform: rotate(360deg);
            }
        }
 
        .button {
            display: none;
            margin-top: 22px;
            width: 100%;
            height: 46px;
            border: 0;
            border-radius: 8px;
            background: #1677ff;
            color: #fff;
            font-size: 15px;
        }
    </style>
</head>
 
<body>
 
<div class="box">
 
    <div class="icon" id="icon">&#128179;</div>
 
    <div class="title" id="title">
        正在跳转收款页面
    </div>
 
    <div class="desc" id="desc">
        请稍候...
    </div>
 
    <div class="loading" id="loading"></div>
 
    <button class="button" id="button">
        点击继续
    </button>
 
</div>
 
<script>
(function () {
 
    // ==============================
    // 收款地址
    // ==============================
 
    const PAY_URL = {
        wechat: "https://payapp.wechatpay.cn/sjt/qr/AQHcRjMZMLHpYnXkgZnw4jtU#",
 
        alipay: "https://qr.alipay.com/2m618208kwnpfxzl24zfbfb"
    };
 
 
    // ==============================
    // 获取 URL 参数
    // ==============================
 
    function getParam(name) {
        const params = new URLSearchParams(window.location.search);
        return params.get(name);
    }
 
 
    // ==============================
    // 判断当前环境
    // ==============================
 
    function detectPayType() {
 
        // 第一优先级:URL 参数
        //
        // ?type=wechat
        // ?type=alipay
 
        const type = (getParam("type") || "").toLowerCase();
 
        if (type === "wechat" || type === "wx") {
            return "wechat";
        }
 
        if (type === "alipay" || type === "ali" || type === "zfb") {
            return "alipay";
        }
 
 
        // 第二优先级:UA 判断
        const ua = navigator.userAgent.toLowerCase();
 
 
        // 微信
        if (
            ua.indexOf("micromessenger") !== -1 ||
            ua.indexOf("wechat") !== -1
        ) {
            return "wechat";
        }
 
 
        // 支付宝
        if (
            ua.indexOf("alipayclient") !== -1 ||
            ua.indexOf("aliapp") !== -1
        ) {
            return "alipay";
        }
 
 
        // 无法判断
        return null;
    }
 
 
    // ==============================
    // 更新页面
    // ==============================
 
    function showPayType(type) {
 
        const icon = document.getElementById("icon");
        const title = document.getElementById("title");
        const desc = document.getElementById("desc");
        const loading = document.getElementById("loading");
        const button = document.getElementById("button");
 
 
        if (type === "wechat") {
 
            icon.innerHTML = "&#128154;";
 
            title.innerHTML = "正在打开微信支付";
 
            desc.innerHTML = "即将跳转到微信收款页面,请稍候...";
 
            setTimeout(function () {
                window.location.replace(PAY_URL.wechat);
            }, 300);
 
            return;
        }
 
 
        if (type === "alipay") {
 
            icon.innerHTML = "&#128153;";
 
            title.innerHTML = "正在打开支付宝";
 
            desc.innerHTML = "即将跳转到支付宝收款页面,请稍候...";
 
            setTimeout(function () {
                window.location.replace(PAY_URL.alipay);
            }, 300);
 
            return;
        }
 
 
        // ==============================
        // 无法判断
        // ==============================
 
        icon.innerHTML = "&#128179;";
 
        title.innerHTML = "选择支付方式";
 
        desc.innerHTML = "请选择您要使用的支付方式";
 
        loading.style.display = "none";
 
 
        button.style.display = "block";
        button.innerHTML = "打开微信支付";
 
        button.onclick = function () {
            window.location.href = PAY_URL.wechat;
        };
 
 
        const aliButton = document.createElement("button");
 
        aliButton.className = "button";
        aliButton.style.display = "block";
        aliButton.style.marginTop = "10px";
        aliButton.innerHTML = "打开支付宝";
 
        aliButton.onclick = function () {
            window.location.href = PAY_URL.alipay;
        };
 
        button.parentNode.appendChild(aliButton);
    }
 
 
    // ==============================
    // 开始检测
    // ==============================
 
    const payType = detectPayType();
 
    showPayType(payType);
 
})();
</script>
 
</body>
</html>

两个小提示:一是微信经营码申请和收款码 URL 解码时注意时效,部分链接带有效期,掉链了重新解码替换即可;二是支付宝 App 内打开非阿里的域名会提示"非支付宝页面",属正常现象,不影响支付流程。整套东西部署到 GitHub Pages、Codeberg Pages 这类免费静态托管上,配个短域名或短链,就能当正式收款入口用了。