Skip to content

fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新(#4279) - #4272

Open
Georgyhongbo wants to merge 2 commits into
opentiny:devfrom
Georgyhongbo:fix/tabs-showmore-overflow
Open

fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新(#4279)#4272
Georgyhongbo wants to merge 2 commits into
opentiny:devfrom
Georgyhongbo:fix/tabs-showmore-overflow

Conversation

@Georgyhongbo

@Georgyhongbo Georgyhongbo commented Jul 29, 2026

Copy link
Copy Markdown

PR

PR Checklist

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

  • Bugfix

What is the current behavior?

image image image

Tabs 组件在 showMoreTabs 模式下,"更多"下拉菜单的溢出计算(calcMorePanes)存在滞后问题,表现为以下场景:

  1. 初始加载时:不可见的 tab 中,最靠左的一个没有出现在下拉菜单中(例如 tabs 1-5 可见,6-8 不可见,但下拉菜单只有 7、8,缺少 6)

  2. 从下拉菜单点击 tab 后scrollToActiveTab 将 nav 滚动到目标 tab,使其变为可见,但下拉菜单中的内容不会更新——已变为可见的 tab 仍然显示在下拉菜单中

  3. 点击可见 tab 后:上一步下拉菜单中滞留的 tab 此时才消失,表现为"慢一拍"——上一个动作的结果在下一个动作时才结算

  4. 连续操作:从下拉菜单选 tab8 → 点回 tab4 → 点 < 箭头 → 下拉菜单打开失败或内容错误

根因有两点:

a) CSS transition 干扰坐标读取nav 元素上有 transition: transform 0.3s。当 scrollToActiveTab 改变 navOffset 触发滚动时,tab 位置通过 CSS 动画在 0.3s 内逐渐过渡到新位置。但 calcMorePanesrequestAnimationFrame 回调中运行——此时 transition 尚未推进(动画尚未开始或刚处于第 0 帧),getBoundingClientRect() 返回的是过渡前的位置,导致溢出判断基于旧坐标。

b) 级联 DOM 更新未充分等待scrollToActiveTab 修改 navOffset → TabNav 重渲染 → updated() 回调可能再次调整 navOffset(clamping)→ 再次重渲染。这是一个级联的微任务链,nextTickPromise.then)只能等一轮 flush,无法保证所有级联更新都已落定。

What is the new behavior?

  1. 所有场景下下拉菜单内容与可见 tab 保持同步:初始加载、从下拉菜单点击 tab、点击箭头滚动后,下拉菜单始终只显示真正不可见的 tab

  2. 消除"慢一拍"滞后:点击 tab 后立即正确计算溢出,不再需要下一个动作才结算

修复方案:

a) Transition 不变公式packages/renderless/src/tabs/index.ts):用 tab 相对于 nav 的位置差(tabRect.left - navRect.left)替代直接使用 tabRect.left + tabRect.width / 2。因为 tab 和 nav 共享同一个 transform 坐标系,CSS transition 对两者的偏移量始终相同,差值恒定不变。再结合目标 navOffset 值推算 transition 完成后的最终视口位置。该公式在有无 transition 的情况下均数学等价于旧公式,但不受 transition 中间状态干扰。

b) requestAnimationFrame 替代 nextTickpackages/renderless/src/tabs/vue.tspackages/vue/src/tabs/src/pc.vue):在 4 处异步刷新点(onMountedonUpdatedcurrentName watcher、模板 render)用 requestAnimationFrame 延迟 calcMorePanes 调用。rAF 在所有微任务(包括级联的 Vue 更新)完成后、浏览器绘制前触发,确保读取到的 DOM 状态是最终落定的。

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

改动文件:

文件 改动说明
packages/renderless/src/tabs/index.ts 重写 calcMorePanes:用 transition 不变的几何公式替代直接坐标比较
packages/renderless/src/tabs/vue.ts onMounted/onUpdated/currentName watcher 三处添加 rAF 延迟重算
packages/vue/src/tabs/src/pc.vue render 函数中 $nextTick 内添加 rAF 延迟重算

showPanesCount 的语义不变(第一个不可见 tab 的索引,等于 tabs.length 时表示无溢出)。新增的 rAF 调用是对即时 calcMorePanes() 的补充,即时调用仍然保留以确保首次渲染和 scrollPrev/scrollNext 等场景的即时响应。

Summary by CodeRabbit

  • Bug Fixes
    • Improved tab overflow detection when “Show more tabs” is enabled.
    • Tabs now update more consistently after switching tabs and after using previous/next arrows by recalculating overflow after animations.
    • Prevented errors when the tab navigation element is missing.
    • Better support for tabs with dynamic widths and accurate positioning.

…ansition

The nav element has CSS transition: transform 0.3s, which causes
getBoundingClientRect() to return pre-transition positions when
calcMorePanes runs in requestAnimationFrame (before the transition
has advanced).

Fix: use tab-relative-to-nav position delta (transition-invariant
since both share the same transform coordinate space) plus navOffset
to compute the final expected positions, bypassing the transition
intermediate state entirely.

Also replace nextTick with requestAnimationFrame in deferred
calcMorePanes calls to ensure all cascading DOM updates from
scrollToActiveTab -> updated() chains have settled.
@github-actions github-actions Bot added the bug Something isn't working label Jul 29, 2026
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Tabs overflow detection now uses tab and navigation bounding rectangles. Recalculation is exposed through the renderless API and deferred with requestAnimationFrame after navigation, lifecycle updates, component refreshes, and arrow scrolling.

Changes

Tabs overflow recalculation

Layer / File(s) Summary
Geometry-based overflow calculation
packages/renderless/src/tabs/index.ts
calcMorePanes now uses bounding-rectangle geometry to determine hidden tabs, with explicit handling for empty tabs and moreShowAll.
Deferred recalculation wiring
packages/renderless/src/tabs/vue.ts, packages/vue/src/tabs/src/pc.vue, packages/renderless/src/tab-nav/index.ts
calcMorePanes is exposed and scheduled after active-tab navigation, lifecycle updates, component refreshes, and arrow scrolling; navigation refs are guarded before forcing updates.

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

Possibly related PRs

Suggested reviewers: zzcr

Poem

I’m a bunny with tabs in a row,
Measuring centers wherever they go.
With frames hopping late,
Overflow meets its fate—
And hidden panes now know when to show!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了 showMoreTabs 下 overflow 计算滞后导致更多下拉菜单未及时更新的修复。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@Georgyhongbo

Copy link
Copy Markdown
Author

@shenjunjian 能麻烦审核一下吗,谢谢

@Issues-translate-bot

Copy link
Copy Markdown

Bot detected the issue body's language is not English, translate it automatically.


@shenjunjian Could you please review it? Thank you.

@Georgyhongbo Georgyhongbo changed the title fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新 fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新(#4278) Jul 30, 2026
@Georgyhongbo Georgyhongbo changed the title fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新(#4278) fix(tabs): 修复 showMoreTabs 模式下 overflow 计算滞后导致下拉菜单未及时更新(#4279) Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants