Files
wx-h5-demo/index.html

243 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
<meta name="theme-color" content="#F4593C">
<title>wx-h5-demo · 共享授权规范示例</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
body { font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif; background:#F8F3EF; color:#2B2320; min-height:100vh; display:flex; justify-content:center; }
.wrap { width:100%; max-width:430px; padding:24px 20px 40px; }
.brand { font-size:22px; font-weight:800; color:#F4593C; } .brand small{color:#A79C95;font-size:13px;font-weight:500;margin-left:8px}
.env { margin:14px 0 8px; font-size:13px; color:#6B615B; } .env b{color:#2B2320}
.tag { display:inline-block; padding:2px 8px; border-radius:8px; font-size:12px; }
.tag.ok{background:#E8F2EB;color:#5F8A4A} .tag.no{background:#F6DCD6;color:#C4553A}
.card { background:#fff; border:1px solid #EFE7E1; border-radius:16px; padding:16px; margin-top:14px; }
.card h2{font-size:15px;font-weight:800;margin-bottom:10px}
.row{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px dashed #EFE7E1;font-size:14px}
.row:last-child{border-bottom:none} .row .k{color:#6B615B} .row .v{font-weight:600} .row .v.placeholder{color:#C9B7AC;font-weight:500}
.avatar{width:44px;height:44px;border-radius:50%;background:#F1E6E0;overflow:hidden;display:flex;align-items:center;justify-content:center;font-size:18px}
.avatar img{width:100%;height:100%;object-fit:cover}
.btn{display:block;width:100%;padding:15px;border:none;border-radius:14px;font-size:15px;font-weight:700;margin-top:14px;cursor:pointer}
.btn.main{background:#F4593C;color:#fff} .btn.ghost{background:#fff;color:#6B615B;border:1px solid #EFE7E1}
.hint{font-size:12px;color:#A79C95;margin-top:12px;line-height:1.6}
#toast{position:fixed;left:50%;bottom:14%;transform:translateX(-50%);background:rgba(30,22,18,.9);color:#fff;padding:10px 18px;border-radius:10px;font-size:13px;opacity:0;pointer-events:none;transition:opacity .25s;z-index:99}
#toast.show{opacity:1}
/* ==== 调试日志面板 ==== */
#dbgToggle{position:fixed;right:12px;bottom:12px;z-index:200;background:#2B2320;color:#fff;border:none;border-radius:20px;padding:9px 14px;font-size:13px;font-weight:700;box-shadow:0 4px 14px rgba(0,0,0,.25);cursor:pointer;opacity:.92}
#dbgPanel{position:fixed;right:0;bottom:0;left:0;z-index:210;background:#1A1512;color:#E7DAD1;font-family:Menlo,Consolas,monospace;font-size:12px;line-height:1.5;border-top:2px solid #F4593C;transform:translateY(100%);transition:transform .25s;max-height:62vh;display:flex;flex-direction:column}
#dbgPanel.open{transform:translateY(0)}
#dbgHead{display:flex;justify-content:space-between;align-items:center;padding:9px 12px;background:#241D18;border-bottom:1px solid #3A2F28}
#dbgHead b{font-size:13px;color:#F4593C}
#dbgHead span{font-size:11px;color:#A79C95}
#dbgHead button{margin-left:8px;background:none;border:1px solid #4A3D34;color:#E7DAD1;border-radius:6px;padding:3px 10px;font-size:12px;cursor:pointer}
#dbgLog{overflow-y:auto;padding:8px 12px;flex:1;word-break:break-all}
#dbgLog .ln{margin:3px 0;padding:3px 6px;border-left:3px solid #4A3D34;color:#CBBDB2}
#dbgLog .ln.err{border-left-color:#F4593C;color:#FF9E86;background:rgba(244,89,60,.08)}
#dbgLog .ln.ok{border-left-color:#5F8A4A;color:#9BC48A}
#dbgLog .ln.warn{border-left-color:#E0B33E;color:#EED49A}
#dbgLog .ln.muted{color:#8B7E75;border-left-color:#3A2F28}
#dbgLog .ln b{color:#fff;font-weight:700}
</style>
</head>
<body>
<div class="wrap">
<div class="brand">wx-h5-demo <small>共享授权规范示例</small></div>
<div class="env">环境:<b id="envTxt">检测中…</b> <span id="envTag" class="tag no">纯浏览器</span></div>
<div class="card">
<h2>授权状态</h2>
<p id="authState" style="font-size:13px;color:#6B615B;line-height:1.6">检测中…</p>
<button class="btn main" id="btnAuth" style="display:none">授权登录</button>
<button class="btn ghost" id="btnMall">进商城</button>
</div>
<div class="card">
<h2>授权结果(宿主页回传后读取 #phone/nickname/avatar)</h2>
<div class="row"><span class="k">手机号</span><span class="v placeholder" id="rPhone">—</span></div>
<div class="row"><span class="k">昵称</span><span class="v placeholder" id="rNick">—</span></div>
<div class="row"><span class="k">头像</span><span class="v"><span class="avatar" id="rAvatarWrap"><span id="rAvatarText">宝</span></span></span></div>
</div>
<p class="hint">
本页演示<b>共享授权规范</b>:<code>wx-auth.js</code>(<code>wxAuth.init/requestProfile/goMall/readAuth/isAuthorized</code>)。
授权流程:点「授权登录」→ <code>wx.miniProgram.navigateTo('/pages/annex/auth/index')</code> →
小程序端独立授权页(头像/昵称/手机号,非 web-view 原生组件页)→ <code>POST /api/mp/public/auth/profile</code> 落库共享 UserAuth →
授权返回后宿主页更新 <code>web-view src</code>(hash 带结果)→ 本页重载 → <code>wxAuth.readAuth()</code> 显示。
「进商城」→ <code>wx.miniProgram.switchTab('/pages/goods_cate/goods_cate')</code>。
</p>
<div id="ver" style="text-align:center;color:#B3A69C;font-size:11px;margin-top:22px;padding-bottom:8px">v<span id="verNo"></span></div>
</div>
<div id="toast"></div>
<!-- 调试日志面板 -->
<button id="dbgToggle">🐛 调试日志</button>
<div id="dbgPanel">
<div id="dbgHead">
<b>调试日志</b>
<span id="dbgCount"></span>
<span>
<button id="dbgCopy">复制</button>
<button id="dbgClear">清空</button>
<button id="dbgClose">收起</button>
</span>
</div>
<div id="dbgLog"></div>
</div>
<script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
<script src="wx-auth.js"></script>
<script>
(function () {
'use strict';
/* ============================================================
① 页面版本号(YYMMDD + 两位序号)—— 用于排查 webview 是否缓存了旧页面
============================================================ */
var VER = '26090802';
var verNoEl = el('verNo');
if (verNoEl) verNoEl.textContent = VER;
/* ============================================================
② 日志面板(真机上 console/alert 看不到,用可视化面板)
============================================================ */
var dbgCount = 0;
function el(id) { return document.getElementById(id); }
function dbg(msg, cls) {
dbgCount++;
var logBox = el('dbgLog');
var ln = document.createElement('div');
ln.className = 'ln' + (cls ? ' ' + cls : '');
var t = new Date().toTimeString().replace(/.*(\d\d:\d\d:\d\d).*/, '$1');
ln.innerHTML = '<b>' + t + '</b> ' + msg;
logBox.appendChild(ln);
logBox.scrollTop = logBox.scrollHeight;
el('dbgCount').textContent = '共 ' + dbgCount + ' 条';
try { console.log('[dbg]', msg); } catch (e) {}
}
function dbgErr(msg) { dbg('❌ ' + msg, 'err'); }
window.__dbg = dbg;
// 全局错误捕获
window.addEventListener('error', function (e) {
dbgErr('window.onerror: ' + (e.message || '未知') + ' @ ' + (e.filename || '') + ':' + (e.lineno || '') + ':' + (e.colno || ''));
});
window.addEventListener('unhandledrejection', function (e) {
var r = e.reason;
dbgErr('unhandledrejection: ' + (r && (r.message || r.stack) ? (r.message || r.stack) : r));
});
// 面板开关
el('dbgToggle').addEventListener('click', function () { el('dbgPanel').classList.toggle('open'); });
el('dbgClose').addEventListener('click', function () { el('dbgPanel').classList.remove('open'); });
el('dbgClear').addEventListener('click', function () { el('dbgLog').innerHTML = ''; dbgCount = 0; el('dbgCount').textContent = ''; });
// 复制日志:隐藏 textarea + execCommand('copy'),微信 webview 通用做法
el('dbgCopy').addEventListener('click', function () {
var text = '';
var lns = el('dbgLog').querySelectorAll('.ln');
for (var i = 0; i < lns.length; i++) {
var t = (lns[i].querySelector('b') ? lns[i].querySelector('b').textContent : '');
text += t + ' ' + lns[i].textContent.replace(t, '').trim() + '\n';
}
text = '[wx-h5-demo 调试日志 v' + VER + ']\n' + text;
function ok() { dbg('已复制 ' + lns.length + ' 条日志到剪贴板', 'ok'); }
try {
var ta = document.createElement('textarea');
ta.value = text;
ta.style.cssText = 'position:fixed;top:0;left:0;opacity:0;height:1px;width:1px;overflow:hidden';
document.body.appendChild(ta);
ta.select();
var did = document.execCommand('copy');
document.body.removeChild(ta);
if (did) ok(); else dbgErr('复制失败(execCommand 返回 false)');
} catch (e) {
dbgErr('复制失败: ' + (e && e.message ? e.message : e));
}
});
function show(tag, title) {
el('envTag').textContent = title; el('envTag').className = 'tag ' + (tag === 'ok' ? 'ok' : 'no');
}
/* ============================================================
② jweixin / wx.miniProgram 环境检测(先记录关键前提)
============================================================ */
dbg('脚本初始化开始');
dbg('jweixin 已加载: window.wx = ' + (typeof window.wx !== 'undefined' ? '✅ 存在' : '❌ 不存在(CDN 加载失败或未进入微信环境)'));
dbg('window.wx.miniProgram = ' + ((window.wx && window.wx.miniProgram) ? '✅ 存在' : '❌ 不存在'), 'muted');
dbg('navigator.userAgent 含 MicroMessenger: ' + (/MicroMessenger/i.test(navigator.userAgent) ? '✅ 是' : '❌ 否'), 'muted');
dbg('location.hash = ' + (location.hash || '(空)') + ' location.search = ' + (location.search || '(空)'), 'muted');
// 给 navigateTo 打补丁:记录每一次跳转调用 + 捕获异常
if (window.wx && window.wx.miniProgram && window.wx.miniProgram.navigateTo) {
var _nav = window.wx.miniProgram.navigateTo.bind(window.wx.miniProgram);
window.wx.miniProgram.navigateTo = function (o) {
dbg('navigateTo 调用 → ' + (o && o.url), 'ok');
try { _nav(o); dbg('navigateTo 已执行', 'ok'); }
catch (ex) { dbgErr('navigateTo 抛异常: ' + (ex && ex.message ? ex.message : ex)); }
};
}
// 给 postMessage 打补丁:记录每一次调用 + 捕获异常
var origPost = (window.wx && window.wx.miniProgram && window.wx.miniProgram.postMessage) ? window.wx.miniProgram.postMessage.bind(window.wx.miniProgram) : null;
if (window.wx && window.wx.miniProgram) {
window.wx.miniProgram.postMessage = function (msg) {
dbg('postMessage 调用 → ' + JSON.stringify(msg), 'ok');
if (!origPost) { dbgErr('postMessage: 无原始方法,无法发送'); return; }
try { origPost(msg); dbg('postMessage 已发送', 'ok'); }
catch (ex) { dbgErr('postMessage 抛异常: ' + (ex && ex.message ? ex.message : ex)); }
};
} else {
dbg('未安装 postMessage 补丁(wx.miniProgram 不存在)', 'warn');
}
/* ============================================================
③ 页面数据渲染
============================================================ */
function render(a) {
var authed = a.isAuthorized();
dbg('render(): isAuthorized=' + authed + ' readAuth=' + JSON.stringify(a.readAuth()), 'muted');
el('authState').textContent = authed ? '✅ 已授权(昵称/头像/手机号)' : '🔓 未授权,点下方「授权登录」';
el('btnAuth').style.display = authed ? 'none' : 'block';
el('rPhone').textContent = a.readAuth().phone || '—';
el('rNick').textContent = a.readAuth().nickname || '—';
if (a.readAuth().avatar) { el('rAvatarWrap').innerHTML = '<img src="' + a.readAuth().avatar + '" alt="头像">'; }
}
/* ============================================================
④ 初始化:环境检测 + 读取授权
============================================================ */
function init() {
wxAuth.init(function (a) {
var envTxt = a.inWebview ? '小程序 web-view' : (a.MODE === 'wechat-browser' ? '微信浏览器' : '纯浏览器');
dbg('init 回调: envTxt=' + envTxt + ' MODE=' + a.MODE + ' inWebview=' + a.inWebview, 'ok');
el('envTxt').textContent = envTxt;
render(a);
});
}
document.addEventListener('DOMContentLoaded', function () {
init();
el('btnAuth').addEventListener('click', function () {
dbg('🖱️ 点击「授权登录」按钮');
if (!(window.wx && window.wx.miniProgram)) {
dbgErr('requestProfile 被拒绝:window.wx.miniProgram 不存在(不在微信 web-view 或 jweixin 未加载)');
} else {
dbg('requestProfile 前置检查通过(wx.miniProgram 存在),开始 navigateTo 授权页', 'ok');
}
wxAuth.requestProfile();
});
el('btnMall').addEventListener('click', function () {
dbg('🖱️ 点击「进商城」按钮');
wxAuth.goMall();
});
});
})();
</script>
</body>
</html>