Skip to content

Support scrollbar track click#368

Open
QDyanbing wants to merge 1 commit into
react-component:masterfrom
QDyanbing:scrollbar-track-click
Open

Support scrollbar track click#368
QDyanbing wants to merge 1 commit into
react-component:masterfrom
QDyanbing:scrollbar-track-click

Conversation

@QDyanbing

@QDyanbing QDyanbing commented Jul 3, 2026

Copy link
Copy Markdown

变更内容

  • 为虚拟滚动下的自定义滚动条补充点击轨道快速定位能力。
  • 抽出滚动条滑块位置到滚动偏移的计算逻辑,并复用于拖拽与轨道点击,保持边界处理一致。
  • 新增竖向滚动条轨道点击的回归测试。

背景

Ant Design issue ant-design/ant-design#58499 反馈:Table 开启虚拟滚动后,自定义滚动条仅支持拖拽滑块或滚轮滚动,不支持点击滚动条轨道快速定位。该交互与浏览器原生滚动条体验不一致。

影响

虚拟滚动列表的自定义滚动条现在可以通过点击轨道直接跳转到对应滚动位置;点击滑块本身仍保持原来的拖拽行为。

验证

  • npm run lint:通过,存在仓库既有 hooks warnings,无 error。
  • npm run tsc:通过。
  • npm test -- tests/scroll.test.js --runInBand:通过。
  • npm test -- tests/scrollWidth.test.tsx --runInBand:通过。
  • git diff --check:通过。

Summary by CodeRabbit

  • Bug Fixes

    • 优化滚动条交互,拖动滑块和点击轨道时的滚动位置计算更一致,避免越界或无效滚动。
    • 修复点击滚动条轨道时的响应问题,非左键或点中滑块时不再误触发滚动。
  • Tests

    • 新增滚动条轨道点击滚动的测试,覆盖点击后列表滚动位置更新。

@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

@QDyanbing is attempting to deploy a commit to the afc163's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3e3f0fb0-fff6-4071-92ae-8a4f04866ce7

📥 Commits

Reviewing files that changed from the base of the PR and between cf92789 and 905b481.

📒 Files selected for processing (2)
  • src/ScrollBar.tsx
  • tests/scroll.test.js

Walkthrough

重构了 ScrollBar 中滚动偏移的计算逻辑,新增 getScrollOffsetByThumbTop 工具函数统一处理拖拽与轨道点击场景下的比例换算和边界裁剪,新增 isThumbTarget 与 scrollToTrackPosition 处理点击判定,并补充相应测试用例。

Changes

滚动条偏移计算重构

Layer / File(s) Summary
偏移换算工具函数
src/ScrollBar.tsx
新增 getScrollOffsetByThumbTop,统一 thumbTop 到滚动偏移的比例换算与边界裁剪。
轨道点击处理与 thumb 识别
src/ScrollBar.tsx
新增 isThumbTarget 与 scrollToTrackPosition,调整 onContainerMouseDown 短路条件,非左键或点击 thumb 时不触发轨道滚动。
拖拽滚动计算迁移与测试
src/ScrollBar.tsx, tests/scroll.test.js
拖拽计算改用 getScrollOffsetByThumbTop 替代旧的 ptg 计算逻辑,新增“点击轨道滚动”测试用例验证 scrollTop。

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ScrollBar
  participant getScrollOffsetByThumbTop
  participant onScroll

  User->>ScrollBar: mouseDown on track
  ScrollBar->>ScrollBar: isThumbTarget(target)
  alt 非左键点击或点击目标为thumb
    ScrollBar-->>User: 直接返回
  else 点击轨道空白处
    ScrollBar->>ScrollBar: scrollToTrackPosition(mousePos)
    ScrollBar->>getScrollOffsetByThumbTop: 计算thumbTop对应scrollOffset
    getScrollOffsetByThumbTop-->>ScrollBar: 返回裁剪后偏移
    ScrollBar->>onScroll: 触发滚动
  end
Loading

Possibly related PRs

Suggested reviewers: MadCcc

Poem

轨道点击轻轻按,🐰
拇指偏移算得妙,
边界裁剪不出错,
拖拽点击一条路,
兔子蹦跳测试跑,
滚动流畅心欢笑!🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次为滚动条轨道点击提供支持的核心变更。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/ScrollBar.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

tests/scroll.test.js

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@QDyanbing QDyanbing marked this pull request as ready for review July 3, 2026 01:08

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces track-clicking functionality to the ScrollBar component, allowing users to scroll by clicking directly on the scrollbar track. It extracts the scroll offset calculation into a reusable helper function getScrollOffsetByThumbTop and adds a vertical track-clicking test. The review feedback suggests improving the robustness of the new helper function by handling non-finite range values, and expanding test coverage to include horizontal track-clicking scenarios under both LTR and RTL layouts.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/ScrollBar.tsx
Comment on lines +33 to +35
if (enabledScrollRange <= 0 || enabledOffsetRange <= 0) {
return 0;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

getScrollOffsetByThumbTop 中,如果 enabledScrollRangeenabledOffsetRangeNaN 或非有限数值(例如在组件初始挂载、尺寸尚未测量完成时),enabledScrollRange <= 0 的判断会返回 false,从而导致后续计算产生 NaN 并传递给 onScroll

建议使用 Number.isFinite 进行更严谨的防御性检查,确保计算结果的安全性。

Suggested change
if (enabledScrollRange <= 0 || enabledOffsetRange <= 0) {
return 0;
}
if (
!Number.isFinite(enabledScrollRange) ||
!Number.isFinite(enabledOffsetRange) ||
enabledScrollRange <= 0 ||
enabledOffsetRange <= 0
) {
return 0;
}

Comment thread tests/scroll.test.js
Comment on lines +311 to +326
it('click track to scroll', () => {
const { container } = genList({
itemHeight: 20,
height: 100,
data: genData(100),
});

act(() => {
const scrollbar = container.querySelector('.rc-virtual-list-scrollbar-vertical');
const mouseDownEvent = createEvent.mouseDown(scrollbar);
Object.defineProperty(mouseDownEvent, 'pageY', { value: 50 });
fireEvent(scrollbar, mouseDownEvent);
});

expect(container.querySelector('ul').scrollTop).toEqual(950);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

虽然新增了竖向滚动条轨道点击的测试,但水平滚动条(尤其是涉及 RTL 和 LTR 逻辑的分支)也包含了较为复杂的坐标计算。

建议补充水平滚动条在 LTR 和 RTL 模式下轨道点击的测试用例,以确保其正确性并防止后续重构引入回归问题。

    it('click track to scroll', () => {
      const { container } = genList({
        itemHeight: 20,
        height: 100,
        data: genData(100),
      });

      act(() => {
        const scrollbar = container.querySelector('.rc-virtual-list-scrollbar-vertical');
        const mouseDownEvent = createEvent.mouseDown(scrollbar);
        Object.defineProperty(mouseDownEvent, 'pageY', { value: 50 });
        fireEvent(scrollbar, mouseDownEvent);
      });

      expect(container.querySelector('ul').scrollTop).toEqual(950);
    });

    it('click horizontal track to scroll', () => {
      const { container } = genList({
        itemHeight: 20,
        height: 100,
        data: genData(100),
        scrollWidth: 1000,
      });

      act(() => {
        const scrollbar = container.querySelector('.rc-virtual-list-scrollbar-horizontal');
        const mouseDownEvent = createEvent.mouseDown(scrollbar);
        Object.defineProperty(mouseDownEvent, 'pageX', { value: 50 });
        fireEvent(scrollbar, mouseDownEvent);
      });

      const horizontalScrollbar = container.querySelector('.rc-virtual-list-scrollbar-horizontal');
      expect(Number(horizontalScrollbar.parentElement.getAttribute('data-dev-offset'))).toEqual(450);
    });

    it('click horizontal track to scroll in RTL', () => {
      const { container } = genList({
        itemHeight: 20,
        height: 100,
        data: genData(100),
        scrollWidth: 1000,
        direction: 'rtl',
      });

      act(() => {
        const scrollbar = container.querySelector('.rc-virtual-list-scrollbar-horizontal');
        const mouseDownEvent = createEvent.mouseDown(scrollbar);
        Object.defineProperty(mouseDownEvent, 'pageX', { value: 50 });
        fireEvent(scrollbar, mouseDownEvent);
      });

      const horizontalScrollbar = container.querySelector('.rc-virtual-list-scrollbar-horizontal');
      expect(Number(horizontalScrollbar.parentElement.getAttribute('data-dev-offset'))).toEqual(450);
    });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant