import './wb-legacy-disabled.mjs' /** * 首页补充探测:大标题、输入框下方行、建议列表。 * * 用法:node scripts/wb-home-parts.mjs */ const port = Number(process.argv[2] ?? 9223) async function main() { const list = await (await fetch(`http://127.0.0.1:${port}/json/list`)).json() const page = list.filter((t) => t.type === 'page')[0] const ws = new WebSocket(page.webSocketDebuggerUrl) await new Promise((r, j) => { const t = setTimeout(() => j(new Error('连接超时')), 8000) ws.addEventListener('open', () => { clearTimeout(t) r() }) ws.addEventListener('error', () => { clearTimeout(t) j(new Error('连接失败')) }) }) const send = (method, params = {}) => new Promise((res, rej) => { const id = Math.floor(Math.random() * 1e9) const timer = setTimeout(() => rej(new Error(`超时 ${method}`)), 25000) const h = (ev) => { const m = JSON.parse(ev.data) if (m.id === id) { clearTimeout(timer) ws.removeEventListener('message', h) res(m.result) } } ws.addEventListener('message', h) ws.send(JSON.stringify({ id, method, params })) }) const expr = `(() => { const clean = (v) => (v == null ? '' : String(v).replace(/\\s+/g, ' ').trim()); const R = (el) => { const r = el.getBoundingClientRect(); return [Math.round(r.x), Math.round(r.y), Math.round(r.width), Math.round(r.height)]; }; const info = (el) => { if (!el) return null; const cs = getComputedStyle(el); return { tag: el.tagName.toLowerCase(), cls: clean(el.className).slice(0, 80), rect: R(el), fontSize: cs.fontSize, fontWeight: cs.fontWeight, lineHeight: cs.lineHeight, color: cs.color, display: cs.display, flexDirection: cs.flexDirection, alignItems: cs.alignItems, justifyContent: cs.justifyContent, gap: cs.gap, padding: cs.padding, margin: cs.margin, radius: cs.borderRadius, bg: cs.backgroundColor, border: cs.borderTopWidth + ' ' + cs.borderTopColor }; }; // 1) 最大字号元素(标题) let heading = null, maxFs = 0; document.querySelectorAll('body *').forEach((el) => { const r = el.getBoundingClientRect(); if (r.y < 30 || r.y > 350 || r.width < 40 || r.height < 10) return; if (el.children.length > 2) return; const cs = getComputedStyle(el); const fs = parseFloat(cs.fontSize); if (fs > maxFs) { maxFs = fs; heading = el; } }); // 2) 输入框外层容器的全部子元素(含下方那行) const box = document.querySelector('[class*="home-route__input-box"]') || document.querySelector('.cr-input-box'); const boxKids = box ? [...box.children].map((c) => ({ ...info(c), text: clean(c.textContent).slice(0, 50) })) : []; // 3) 建议列表:找 y > 520 且高度 32 左右的成组元素 const suggCandidates = []; document.querySelectorAll('button, [role="button"], div, li').forEach((el) => { const r = el.getBoundingClientRect(); if (r.y < 500 || r.y > 800 || r.height < 24 || r.height > 44 || r.width < 120 || r.width > 700) return; const cs = getComputedStyle(el); if (cs.borderRadius === '0px' && cs.backgroundColor === 'rgba(0, 0, 0, 0)') return; const t = clean(el.textContent); if (!t || t.length > 50) return; suggCandidates.push({ ...info(el), text: t }); }); return JSON.stringify({ viewport: { w: innerWidth, h: innerHeight }, heading: info(heading), box: info(box), boxKids, sugg: suggCandidates.slice(0, 12), suggParent: suggCandidates[0] ? info(suggCandidates[0].parentElement) : null, suggGrand: suggCandidates[0] ? info(suggCandidates[0].parentElement?.parentElement) : null }); })()` const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true }) const d = JSON.parse(r.result.value) console.log(`viewport ${d.viewport.w}x${d.viewport.h}`) const show = (label, o) => { if (!o) return console.log(`\n### ${label}\n (无)`) console.log(`\n### ${label}`) console.log(` ${o.tag}.${o.cls} rect ${JSON.stringify(o.rect)}`) console.log(` fs=${o.fontSize}/${o.fontWeight} lh=${o.lineHeight} color=${o.color}`) console.log(` display=${o.display}/${o.flexDirection} align=${o.alignItems} justify=${o.justifyContent} gap=${o.gap}`) console.log(` pad=${o.padding} margin=${o.margin} radius=${o.radius} bg=${o.bg} border=${o.border}`) if (o.text) console.log(` text="${o.text}"`) } show('大标题', d.heading) show('输入框外层 .cr-input-box', d.box) console.log(`\n### 输入框外层的子元素(${d.boxKids.length})`) for (const k of d.boxKids) { console.log(` ${k.tag}.${k.cls} ${JSON.stringify(k.rect)} gap=${k.gap} pad=${k.padding} radius=${k.radius} bg=${k.bg}`) if (k.text) console.log(` "${k.text}"`) } show('建议项父级', d.suggParent) show('建议项祖父', d.suggGrand) console.log(`\n### 建议项候选(${d.sugg.length})`) for (const s of d.sugg) { console.log(` ${s.tag}.${s.cls} ${JSON.stringify(s.rect)} radius=${s.radius} bg=${s.bg} border=${s.border} fs=${s.fontSize} "${s.text}"`) } ws.close() } main().catch((e) => { console.error('失败:', e.message) process.exit(1) })