Skip to content

feat: 表头吸顶 (Sticky Header) 功能及配套#3323

Open
Alexzjt wants to merge 7 commits intonextfrom
feat/sticky
Open

feat: 表头吸顶 (Sticky Header) 功能及配套#3323
Alexzjt wants to merge 7 commits intonextfrom
feat/sticky

Conversation

@Alexzjt
Copy link
Contributor

@Alexzjt Alexzjt commented Feb 26, 2026

👀 PR includes

✨ Feature

  • 表头吸顶 (Sticky Header) 功能及配套

🎨 Enhance

  • Code style optimization
  • Refactoring
  • Change the UI
  • Improve the performance
  • Type optimization

🐛 Bugfix

🔧 Chore

  • Test case
  • Docs / demos update
  • CI / workflow
  • Release version
  • Other ()

📝 Description

背景与解决的问题:
大型表格在长页面滚动时,用户往往希望表头能够吸附在屏幕顶部,以便在向下滚动查看数据时依然能够清晰识别列的含义。本项目此前缺乏在 window / body 层级滚动时的外部表头吸顶能力。

主要改动点:
本 PR 为 @antv/s2 带来了完整的表头吸顶 (Sticky Header) 功能及配套交互:

  1. 基础表头吸顶 StickyHeaderController:
    • 监听外部滚动容器,滚动超出表格区域时,利用双实例架构(主备表拦截)展示吸顶表头。
    • 配置项 interaction.stickyHeader,并支持自定义 offsetTop(适配存在顶部导航栏的系统)。
  2. 交互能力支持 (enableInteraction):
    • 打通了主副表间的事件和状态桥接。
    • 吸顶状态下支持完整的表头操作:列宽/行高 Resize 调整、组内排序(RANGE_SORT)、树节点及角头全量展开/折叠(ROW_CELL_COLLAPSED)。
  3. 官网案例及修复:
    • 提供了相应的官网 demo ([sticky-header.ts]、scroll-loop.ts),包含 React Playground 案例支持。
    • 修复了双实例渲染导致的回环死锁、透视表事件不通等已知问题。

🖼️ Screenshot

Before After
❌ 滚动后丢失表头列名 iShot_2026-02-26_16 10 53 ✅ 滚动后表头吸顶,并支持 resize、展开和排序 iShot_2026-02-26_16 11 33

🔗 Related issue link

🔍 Self-Check before the merge

  • Add or update relevant docs.
  • Add or update relevant demos.
  • Add or update test case.
  • Add or update relevant TypeScript definitions.

@github-actions github-actions bot added the next 2.0-next 版本的问题 label Feb 26, 2026
@github-actions github-actions bot added the pr(feature) new feature label Feb 26, 2026
@github-actions
Copy link
Contributor

你好 @Alexzjt,非常感谢你的贡献.
为了让代码更健壮, 请根据 贡献指南 补充相应单元测试 (文档改动或其他特殊场景除外), 如果有 API 改动, 请修改 相应的文档.
同时请检查 linttest 相关 CI 是否通过, 如果失败, 请点击 [Details] 按钮查看, 并根据日志修复.

Hello, @Alexzjt, Thanks for your contribution. In order to make the code more robust, please add the corresponding unit tests, and update the docs if there are API changes.
At the same time, please check whether the CI related to lint and test passes. If the CI fails, please click [Details] button to check and repair according to the log.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Alexzjt, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求引入了 @antv/s2 的完整表头吸顶功能,解决了大型表格在长页面滚动时表头易丢失的问题。通过双实例架构和 DOM 代理,实现了表头在滚动时吸附在视口顶部,并支持丰富的交互操作。这一改进显著提升了用户在浏览长表格数据时的体验,确保了列信息的持续可见性和可操作性。

Highlights

  • 表头吸顶功能: 实现了表头吸顶功能,支持在 window 或 body 层级滚动时表头吸附在屏幕顶部。
  • 交互能力支持: 完善了吸顶表头的交互能力,包括列宽/行高调整、组内排序、树节点及角头展开/折叠。
  • 文档与演示: 提供了详细的官网文档和演示案例,方便用户理解和使用。
  • 问题修复: 修复了双实例渲染导致的回环死锁和透视表事件不通等已知问题。
Changelog
  • packages/s2-core/src/common/interface/interaction.ts
    • 新增了 stickyHeader 配置项及其 StickyHeaderOptions 接口定义
  • packages/s2-core/src/index.ts
    • 导出了 StickyHeaderController 类
  • packages/s2-core/src/sheet-type/spread-sheet.ts
    • 集成了 StickyHeaderController,并在生命周期中进行了初始化、同步和销毁
  • packages/s2-core/src/ui/sticky-header/index.ts
    • 新增了 StickyHeaderController 文件的实现,负责表头吸顶的逻辑
  • s2-site/common/interaction.en.md
    • 更新了英文交互文档,增加了 stickyHeader 的说明
  • s2-site/common/interaction.zh.md
    • 更新了中文交互文档,增加了 stickyHeader 的说明
  • s2-site/examples/interaction/advanced/demo/meta.json
    • 为表头吸顶功能添加了新的演示案例元数据
  • s2-site/examples/interaction/advanced/demo/scroll-loop.ts
    • 优化了滚动循环演示,改进了按钮逻辑并在销毁时清除了定时器
  • s2-site/examples/interaction/advanced/demo/sticky-header.ts
    • 新增了表头吸顶功能的演示文件
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov-commenter
Copy link

codecov-commenter commented Feb 26, 2026

Codecov Report

❌ Patch coverage is 66.66667% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.66%. Comparing base (ecdc9c8) to head (bb3e7dd).
⚠️ Report is 789 commits behind head on next.

Files with missing lines Patch % Lines
packages/s2-core/src/sheet-type/spread-sheet.ts 66.66% 3 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             next    #3323      +/-   ##
==========================================
+ Coverage   75.77%   78.66%   +2.89%     
==========================================
  Files         257      224      -33     
  Lines       11994    12485     +491     
  Branches     2464     2836     +372     
==========================================
+ Hits         9088     9821     +733     
+ Misses       1398      957     -441     
- Partials     1508     1707     +199     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

本次 PR 实现了表头吸顶(Sticky Header)功能,这是一个非常实用的特性,尤其对于大数据量表格。整体实现方案采用了双 S2 实例的架构,考虑了滚动容器、交互桥接、性能优化(数据精简)等多个方面,代码质量很高。

我主要提出了几点小建议:

  • sticky-header/index.ts 中有一处重复的 JSDoc 注释,建议移除。
  • sticky-header.ts 示例代码中,建议移除不必要的 as any 类型断言和未使用的 SpreadSheet 导入,以提升代码的类型安全性和整洁度。

除此之外,代码逻辑清晰,考虑周全,是一次出色的功能增强。

@github-actions
Copy link
Contributor

github-actions bot commented Feb 26, 2026

Size Change: +1.98 kB (+0.27%)

Total Size: 744 kB

Filename Size Change
./packages/s2-core/dist/s2.min.js 311 kB +1.98 kB (+0.64%)
ℹ️ View Unchanged
Filename Size
./packages/s2-core/dist/s2-extends.min.js 208 kB
./packages/s2-core/dist/s2.min.css 581 B
./packages/s2-react-components/dist/s2-react-components.min.css 2.55 kB
./packages/s2-react-components/dist/s2-react-components.min.js 123 kB
./packages/s2-react/dist/s2-react.min.css 1.3 kB
./packages/s2-react/dist/s2-react.min.js 38.5 kB
./packages/s2-vue/dist/s2-vue.min.css 3.8 kB
./packages/s2-vue/dist/s2-vue.min.js 54.2 kB

compressed-size-action

@Alexzjt
Copy link
Contributor Author

Alexzjt commented Mar 6, 2026

/gemini review

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

This PR introduces a sticky header feature for the @antv/s2 library, which significantly enhances the user experience for large data tables by keeping the header visible during scrolling. The implementation utilizes a complex but effective dual-instance architecture, demonstrating clear code structure and robust handling of secondary instance lifecycles, state synchronization, and interaction bridging. While no security vulnerabilities were identified, and the code adheres to secure coding practices, a potential bug was found in the data minimization logic that could lead to incorrect header rendering in certain edge cases. Overall, this is a high-quality contribution.

Comment on lines +144 to +156
const values = columns.map((column) => {
const key = isString(column)
? column
: (column as { field: string }).field;

return item[key]?.toString?.();
});

const cacheKey = values.join('');

if (!cache[cacheKey]) {
cache[cacheKey] = item;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

high

minimizeDataCfg 方法中生成 cacheKey 的方式存在两个问题,可能导致 cacheKey 冲突,从而使得吸顶表头渲染不正确:

  1. item[key]?.toString?.()nullundefined 的处理结果都是 undefined,这会导致它们与空字符串 '' 等产生冲突。例如,当列值为 null 时,values 数组中对应的项会是 undefinedjoin 之后可能产生与其他值相同的 cacheKey
  2. values.join('') 没有使用分隔符,当不同列的值组合后可能产生相同的字符串。例如,两列数据 ['1', '23']['12', '3'] 会产生相同的 cacheKey "123"。

建议修改 cacheKey 的生成逻辑,使用 String() 进行类型转换并添加一个特殊的分隔符,以确保其唯一性。

      const values = columns.map((column) => {
        const key = isString(column)
          ? column
          : (column as { field: string }).field;

        return String(item[key]);
      });

      const cacheKey = values.join('\u0000');

      if (!cache[cacheKey]) {
        cache[cacheKey] = item;
      }

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

Labels

next 2.0-next 版本的问题 pr(feature) new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🙏表头支持吸顶 🙏表头吸顶

2 participants