From a42402d4de26a54bdbfafd89d14d3029973466c8 Mon Sep 17 00:00:00 2001 From: Borber Date: Tue, 17 Sep 2024 03:18:07 +0800 Subject: [PATCH] fix: stuttering during scrolling --- CHANGELOG.md | 11 ++++ package.json | 6 +- pnpm-lock.yaml | 113 ++++++++++++++++++++++++++++++-------- src-tauri/Cargo.lock | 12 ++-- src-tauri/Cargo.toml | 2 +- src-tauri/src/tray.rs | 2 +- src-tauri/tauri.conf.json | 2 +- src/App.tsx | 64 +++++++++++++++------ 8 files changed, 160 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5b3092..44a79c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,15 @@ # Changelog +## [0.2.18] + +### 修复 + +- 滚动时的卡顿感, 编写了新的滚动逻辑 +- 偶发模拟复制时 `ctrl` 键抬起未被识别 + +### 更新 + +- 优化代码, 理论上更快了, 资源消耗减少 + ## [0.2.17] ### 修复 diff --git a/package.json b/package.json index e5d1a18..ee365d7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tran", - "version": "0.2.17", + "version": "0.2.18", "description": "简洁, 快速, 划词翻译", "type": "module", "scripts": { @@ -19,8 +19,8 @@ "devDependencies": { "@tauri-apps/cli": "2.0.0-rc.5", "@types/node": "^22.5.5", - "@typescript-eslint/eslint-plugin": "^8.5.0", - "@typescript-eslint/parser": "^8.5.0", + "@typescript-eslint/eslint-plugin": "^8.6.0", + "@typescript-eslint/parser": "^8.6.0", "eslint": "^9.10.0", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-solid": "^0.14.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ab0676d..8224a6d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,11 +25,11 @@ importers: specifier: ^22.5.5 version: 22.5.5 '@typescript-eslint/eslint-plugin': - specifier: ^8.5.0 - version: 8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) + specifier: ^8.6.0 + version: 8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2) '@typescript-eslint/parser': - specifier: ^8.5.0 - version: 8.5.0(eslint@9.10.0)(typescript@5.6.2) + specifier: ^8.6.0 + version: 8.6.0(eslint@9.10.0)(typescript@5.6.2) eslint: specifier: ^9.10.0 version: 9.10.0 @@ -528,8 +528,8 @@ packages: '@types/node@22.5.5': resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} - '@typescript-eslint/eslint-plugin@8.5.0': - resolution: {integrity: sha512-lHS5hvz33iUFQKuPFGheAB84LwcJ60G8vKnEhnfcK1l8kGVLro2SFYW6K0/tj8FUhRJ0VHyg1oAfg50QGbPPHw==} + '@typescript-eslint/eslint-plugin@8.6.0': + resolution: {integrity: sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 @@ -539,8 +539,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.5.0': - resolution: {integrity: sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw==} + '@typescript-eslint/parser@8.6.0': + resolution: {integrity: sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -553,8 +553,12 @@ packages: resolution: {integrity: sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@8.5.0': - resolution: {integrity: sha512-N1K8Ix+lUM+cIDhL2uekVn/ZD7TZW+9/rwz8DclQpcQ9rk4sIL5CAlBC0CugWKREmDjBzI/kQqU4wkg46jWLYA==} + '@typescript-eslint/scope-manager@8.6.0': + resolution: {integrity: sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/type-utils@8.6.0': + resolution: {integrity: sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' @@ -566,6 +570,10 @@ packages: resolution: {integrity: sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.6.0': + resolution: {integrity: sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.5.0': resolution: {integrity: sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -575,16 +583,35 @@ packages: typescript: optional: true + '@typescript-eslint/typescript-estree@8.6.0': + resolution: {integrity: sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + '@typescript-eslint/utils@8.5.0': resolution: {integrity: sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/utils@8.6.0': + resolution: {integrity: sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/visitor-keys@8.5.0': resolution: {integrity: sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.6.0': + resolution: {integrity: sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1619,14 +1646,14 @@ snapshots: dependencies: undici-types: 6.19.8 - '@typescript-eslint/eslint-plugin@8.5.0(@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2))(eslint@9.10.0)(typescript@5.6.2)': dependencies: '@eslint-community/regexpp': 4.11.1 - '@typescript-eslint/parser': 8.5.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/type-utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.5.0 + '@typescript-eslint/parser': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/type-utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.6.0 eslint: 9.10.0 graphemer: 1.4.0 ignore: 5.3.2 @@ -1637,12 +1664,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.5.0(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/parser@8.6.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: - '@typescript-eslint/scope-manager': 8.5.0 - '@typescript-eslint/types': 8.5.0 - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) - '@typescript-eslint/visitor-keys': 8.5.0 + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + '@typescript-eslint/visitor-keys': 8.6.0 debug: 4.3.7 eslint: 9.10.0 optionalDependencies: @@ -1655,10 +1682,15 @@ snapshots: '@typescript-eslint/types': 8.5.0 '@typescript-eslint/visitor-keys': 8.5.0 - '@typescript-eslint/type-utils@8.5.0(eslint@9.10.0)(typescript@5.6.2)': + '@typescript-eslint/scope-manager@8.6.0': dependencies: - '@typescript-eslint/typescript-estree': 8.5.0(typescript@5.6.2) - '@typescript-eslint/utils': 8.5.0(eslint@9.10.0)(typescript@5.6.2) + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/visitor-keys': 8.6.0 + + '@typescript-eslint/type-utils@8.6.0(eslint@9.10.0)(typescript@5.6.2)': + dependencies: + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + '@typescript-eslint/utils': 8.6.0(eslint@9.10.0)(typescript@5.6.2) debug: 4.3.7 ts-api-utils: 1.3.0(typescript@5.6.2) optionalDependencies: @@ -1669,6 +1701,8 @@ snapshots: '@typescript-eslint/types@8.5.0': {} + '@typescript-eslint/types@8.6.0': {} + '@typescript-eslint/typescript-estree@8.5.0(typescript@5.6.2)': dependencies: '@typescript-eslint/types': 8.5.0 @@ -1684,6 +1718,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.6.0(typescript@5.6.2)': + dependencies: + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/visitor-keys': 8.6.0 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.2) + optionalDependencies: + typescript: 5.6.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.5.0(eslint@9.10.0)(typescript@5.6.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) @@ -1695,11 +1744,27 @@ snapshots: - supports-color - typescript + '@typescript-eslint/utils@8.6.0(eslint@9.10.0)(typescript@5.6.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.10.0) + '@typescript-eslint/scope-manager': 8.6.0 + '@typescript-eslint/types': 8.6.0 + '@typescript-eslint/typescript-estree': 8.6.0(typescript@5.6.2) + eslint: 9.10.0 + transitivePeerDependencies: + - supports-color + - typescript + '@typescript-eslint/visitor-keys@8.5.0': dependencies: '@typescript-eslint/types': 8.5.0 eslint-visitor-keys: 3.4.3 + '@typescript-eslint/visitor-keys@8.6.0': + dependencies: + '@typescript-eslint/types': 8.6.0 + eslint-visitor-keys: 3.4.3 + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: acorn: 8.12.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8e66110..93c28b2 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2019,9 +2019,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys 0.8.7", @@ -2917,9 +2917,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "open" @@ -3824,7 +3824,7 @@ dependencies = [ [[package]] name = "selection" version = "1.2.2" -source = "git+https://github.com/Borber/selection.git#6cd9d92f172e0482745789a5787bf7294eea4999" +source = "git+https://github.com/Borber/selection.git#3ae7aaa9f744a5b82262f6a0f948781fe21d2ec9" dependencies = [ "accessibility-ng", "accessibility-sys-ng", @@ -4929,7 +4929,7 @@ dependencies = [ [[package]] name = "tran" -version = "0.2.17" +version = "0.2.18" dependencies = [ "anyhow", "arboard", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index d67d0ac..f0d7373 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tran" -version = "0.2.17" +version = "0.2.18" description = "Tran translate the selected words" authors = ["Borber"] license = "GPLv3" diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 4cfbe0e..34dbf94 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -44,7 +44,7 @@ fn menu(handle: &AppHandle) -> Result> { let github = MenuItem::with_id(handle, "github", "GitHub", true, None::<&str>)?; let telegram = MenuItem::with_id(handle, "telegram", "Telegram", true, None::<&str>)?; - let version = MenuItem::with_id(handle, "version", "v0.2.17", false, None::<&str>)?; + let version = MenuItem::with_id(handle, "version", "v0.2.18", false, None::<&str>)?; let about = Submenu::with_items(handle, "About", true, &[&github, &telegram, &version])?; let exit = MenuItem::with_id(handle, "exit", "Exit", true, None::<&str>)?; Menu::with_items(handle, &[&mode, &key, &theme, &about, &exit]) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index cb90b7d..40d1ecc 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "productName": "Tran", - "version": "0.2.17", + "version": "0.2.18", "identifier": "com.borber.tran", "build": { "beforeDevCommand": "pnpm dev", diff --git a/src/App.tsx b/src/App.tsx index 83dbdef..9750346 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -37,6 +37,8 @@ const App = () => { } onMount(async () => { + const RESULT = document.getElementById("result") as HTMLElement + // 主题 // Theme let theme = await invoke>("theme").then((pos) => { @@ -63,6 +65,8 @@ const App = () => { // Listen to events and display panel await listen>("show", async (pos) => { Result(pos.payload.data) + // 滚动到顶部 + RESULT.scrollTop = 0 // 显示完成后取消临时固定 // After displaying, cancel temporary pin await invoke("untmp") @@ -76,25 +80,53 @@ const App = () => { // 调整滚动范围 // Adjust scroll range - const RESULT = document.getElementById("result")! - - RESULT.addEventListener("wheel", (e) => { - // 阻止浏览器默认行为 - // Prevent browser default behavior - e.preventDefault() + const easeOutCubic = (t: number): number => 1 - Math.pow(1 - t, 3) + const smoothScroll = ( + element: HTMLElement, + target: number, + duration: number + ): void => { + const start = element.scrollTop + const distance = target - start + const startTime = performance.now() + const animation = (currentTime: number): void => { + const progress = Math.min( + (currentTime - startTime) / duration, + 1 + ) + element.scrollTop = start + distance * easeOutCubic(progress) + if (progress < 1) requestAnimationFrame(animation) + } + requestAnimationFrame(animation) + } - const height = 60 - const scrollAmount = e.deltaY > 0 ? height : -height - const newScrollTopWithAmount = RESULT.scrollTop + scrollAmount + let lastScrollTime = 0 + let accumulatedDelta = 0 + let scrollAnimationFrame: number + let scrollTimeoutId: number - // 限制滚动范围 + RESULT.addEventListener("wheel", (e: WheelEvent): void => { + e.preventDefault() + const currentTime = performance.now() + if (currentTime - lastScrollTime > 50) accumulatedDelta = 0 + lastScrollTime = currentTime + accumulatedDelta = + Math.sign(e.deltaY) * + Math.min(Math.abs(accumulatedDelta + e.deltaY), 50) + const newScrollTop = RESULT.scrollTop + accumulatedDelta * 0.5 const maxScrollTop = RESULT.scrollHeight - RESULT.clientHeight - const newScrollTopLimited = Math.min( - Math.max(newScrollTopWithAmount, 0), - maxScrollTop + const targetScrollTop = Math.max( + 0, + Math.min(newScrollTop, maxScrollTop) ) - - RESULT.scrollTo({ top: newScrollTopLimited, behavior: "smooth" }) + cancelAnimationFrame(scrollAnimationFrame) + scrollAnimationFrame = requestAnimationFrame(() => { + smoothScroll(RESULT, targetScrollTop, 150) + }) + clearTimeout(scrollTimeoutId) + scrollTimeoutId = window.setTimeout(() => { + accumulatedDelta = 0 + }, 200) }) window.addEventListener("keydown", async (e) => { @@ -106,7 +138,7 @@ const App = () => { await fetch("https://key.borber.top/TRAN_VERSION").then( async (resp) => { const version = await resp.text() - Update(version != "0.2.17") + Update(version != "0.2.18") } ) })