100 lines
3.8 KiB
JavaScript
100 lines
3.8 KiB
JavaScript
/**
|
||
* 判断当前侧栏的滚动模型:
|
||
* - 滚动条覆盖整条(含上下留白)?还是只在内容区?
|
||
* - 滚到底时,顶部留白是否跟着消失?
|
||
*/
|
||
const { spawn } = require('node:child_process')
|
||
const http = require('node:http')
|
||
|
||
const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'
|
||
const PORT = 9390
|
||
const URL = 'http://localhost:3100/ui/general/button'
|
||
|
||
function get(p) {
|
||
return new Promise((res, rej) => {
|
||
http.get({ host: '127.0.0.1', port: PORT, path: p }, (r) => {
|
||
let d = ''
|
||
r.on('data', (c) => (d += c))
|
||
r.on('end', () => res(JSON.parse(d)))
|
||
}).on('error', rej)
|
||
})
|
||
}
|
||
|
||
;(async () => {
|
||
const chrome = spawn(CHROME, [
|
||
'--headless=new', '--disable-gpu',
|
||
`--remote-debugging-port=${PORT}`,
|
||
'--user-data-dir=' + require('node:os').tmpdir() + '\\dsh-model',
|
||
'--no-first-run', '--window-size=1440,900', URL,
|
||
], { stdio: 'ignore' })
|
||
|
||
let target = null
|
||
for (let i = 0; i < 60; i++) {
|
||
try {
|
||
const l = await get('/json/list')
|
||
target = l.find((t) => t.type === 'page' && t.webSocketDebuggerUrl)
|
||
if (target) break
|
||
} catch (e) { /* retry */ }
|
||
await new Promise((r) => setTimeout(r, 500))
|
||
}
|
||
if (!target) { console.log('NO TARGET'); chrome.kill(); process.exit(1) }
|
||
|
||
const ws = new WebSocket(target.webSocketDebuggerUrl)
|
||
let id = 0
|
||
const pend = new Map()
|
||
ws.addEventListener('message', (e) => {
|
||
const m = JSON.parse(e.data)
|
||
if (m.id && pend.has(m.id)) { pend.get(m.id)(m); pend.delete(m.id) }
|
||
})
|
||
const send = (method, params = {}) => new Promise((res) => {
|
||
const i = ++id
|
||
pend.set(i, res)
|
||
ws.send(JSON.stringify({ id: i, method, params }))
|
||
})
|
||
await new Promise((r) => ws.addEventListener('open', r))
|
||
await send('Page.enable'); await send('Runtime.enable')
|
||
await new Promise((r) => setTimeout(r, 9000))
|
||
|
||
const snap = `(() => {
|
||
const sb = document.querySelector('.VPSidebar');
|
||
const nav = sb.querySelector('.nav');
|
||
const firstLink = sb.querySelector('.g3-nav-link');
|
||
const links = sb.querySelectorAll('.g3-nav-link');
|
||
const last = links[links.length - 1];
|
||
const sr = sb.getBoundingClientRect();
|
||
const c = getComputedStyle(sb);
|
||
const navR = nav.getBoundingClientRect();
|
||
return JSON.stringify({
|
||
scrollTop: Math.round(sb.scrollTop),
|
||
sidebarRect: { top: Math.round(sr.top), bottom: Math.round(sr.bottom), h: Math.round(sr.height) },
|
||
scrollbarTrack: '容器整高 ' + Math.round(sr.height) + 'px',
|
||
paddingTop: c.paddingTop,
|
||
paddingBottom: c.paddingBottom,
|
||
navTop: Math.round(navR.top),
|
||
firstLinkTop: Math.round(firstLink.getBoundingClientRect().top),
|
||
lastLinkBottom: Math.round(last.getBoundingClientRect().bottom),
|
||
// 关键:内容区相对可视区的可见范围
|
||
firstLinkVisible: firstLink.getBoundingClientRect().top >= sr.top,
|
||
}, null, 2);
|
||
})()`
|
||
|
||
console.log('=== 初始(scrollTop=0)===')
|
||
console.log((await send('Runtime.evaluate', { expression: snap, returnByValue: true })).result?.result?.value)
|
||
|
||
await send('Runtime.evaluate', {
|
||
expression: `const sb=document.querySelector('.VPSidebar'); sb.scrollTop = 200;`,
|
||
})
|
||
await new Promise((r) => setTimeout(r, 700))
|
||
console.log('\n=== scrollTop=200(看首行是否上移出顶部留白区)===')
|
||
console.log((await send('Runtime.evaluate', { expression: snap, returnByValue: true })).result?.result?.value)
|
||
|
||
await send('Runtime.evaluate', {
|
||
expression: `const sb=document.querySelector('.VPSidebar'); sb.scrollTop = sb.scrollHeight;`,
|
||
})
|
||
await new Promise((r) => setTimeout(r, 700))
|
||
console.log('\n=== 滚到底 ===')
|
||
console.log((await send('Runtime.evaluate', { expression: snap, returnByValue: true })).result?.result?.value)
|
||
|
||
ws.close(); chrome.kill(); process.exit(0)
|
||
})()
|