141 lines
5.4 KiB
JavaScript
141 lines
5.4 KiB
JavaScript
import './wb-legacy-disabled.mjs'
|
||
|
||
/**
|
||
* 首页补充探测:大标题、输入框下方行、建议列表。
|
||
*
|
||
* 用法:node scripts/wb-home-parts.mjs <port>
|
||
*/
|
||
|
||
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)
|
||
})
|