Files
wx-h5-demo/index.html

259 lines
14 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.postMessage({action:'requestProfile'})</code> →
通用宿主页 <code>pages/annex/web_view</code> 弹原生授权面板(头像/昵称/手机号)→ <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 = '26090701';
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 = ''; });
// 复制日志:拼纯文本(时间 + 内容),Clipboard API 优先,失败/不可用则降级 execCommand
function copyWithFallback(text) {
try {
var ta = document.createElement('textarea');
ta.value = text; ta.style.position = 'fixed'; ta.style.opacity = '0';
document.body.appendChild(ta); ta.select();
var ok2 = document.execCommand('copy');
document.body.removeChild(ta);
return !!ok2;
} catch (e) {
return false;
}
}
// 终极大兜底:两种 API 都失败时,弹出一个可全选/长按的文本区让用户手动复制
function manualCopy(text) {
dbg('自动复制不可用,弹出文本区请长按/全选复制 ↓', 'warn');
var box = el('dbgManual');
if (!box) {
box = document.createElement('div');
box.id = 'dbgManual';
box.style.cssText = 'position:fixed;left:10px;right:10px;top:10px;z-index:300;background:#fff;border:2px solid #F4593C;border-radius:12px;padding:10px;box-shadow:0 6px 20px rgba(0,0,0,.3);max-height:70vh;display:flex;flex-direction:column';
box.innerHTML = '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' +
'<b style="color:#F4593C;font-size:13px">手动复制日志</b>' +
'<button id="dbgManualClose" style="border:1px solid #ddd;background:#fff;border-radius:6px;padding:2px 10px">关闭</button></div>' +
'<textarea id="dbgManualText" style="flex:1;width:100%;min-height:180px;border:1px solid #eee;border-radius:8px;padding:8px;font-family:Menlo,Consolas,monospace;font-size:12px" readonly>' +
text.replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</textarea>' +
'<div style="font-size:11px;color:#999;margin-top:6px">提示:微信里长按文本 → 全选 → 复制。</div>';
document.body.appendChild(box);
el('dbgManualClose').addEventListener('click', function () { box.parentNode.removeChild(box); });
var t = el('dbgManualText');
setTimeout(function () { t.focus(); t.select(); }, 300);
}
}
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'); }
function fallback() { if (copyWithFallback(text)) ok(); else manualCopy(text); }
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(ok, function () { fallback(); });
} else {
fallback();
}
});
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');
// 给 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 存在),开始发送 postMessage', 'ok');
}
wxAuth.requestProfile();
});
el('btnMall').addEventListener('click', function () {
dbg('🖱️ 点击「进商城」按钮');
wxAuth.goMall();
});
});
})();
</script>
</body>
</html>