From 92f373c17fb41cc8da6b2d14e1631f2be766f3ba Mon Sep 17 00:00:00 2001 From: Jungzl <13jungzl@gmail.com> Date: Wed, 1 May 2024 10:51:40 +0800 Subject: [PATCH] fix(IndexBar): render active anchor correctly when passing sticky & stickyOffsetTop (#12837) --- packages/vant/src/index-bar/IndexBar.tsx | 12 +- .../test/__snapshots__/index.spec.jsx.snap | 383 ++++++++++++++++++ .../vant/src/index-bar/test/index.spec.jsx | 46 +++ packages/vant/test/dom.ts | 8 + 4 files changed, 447 insertions(+), 2 deletions(-) diff --git a/packages/vant/src/index-bar/IndexBar.tsx b/packages/vant/src/index-bar/IndexBar.tsx index 6441281d3..ab136180f 100644 --- a/packages/vant/src/index-bar/IndexBar.tsx +++ b/packages/vant/src/index-bar/IndexBar.tsx @@ -140,7 +140,11 @@ export default defineComponent({ const match = getMatchAnchor(selectActiveIndex); if (match) { const rect = match.getRect(scrollParent.value, scrollParentRect); - active = getActiveAnchor(rect.top, rects); + if (props.sticky && props.stickyOffsetTop) { + active = getActiveAnchor(rect.top - props.stickyOffsetTop, rects); + } else { + active = getActiveAnchor(rect.top, rects); + } } } else { active = getActiveAnchor(scrollTop, rects); @@ -229,7 +233,11 @@ export default defineComponent({ } if (props.sticky && props.stickyOffsetTop) { - setRootScrollTop(getRootScrollTop() - props.stickyOffsetTop); + if (getRootScrollTop() === offsetHeight - scrollParentRect.height) { + setRootScrollTop(getRootScrollTop()); + } else { + setRootScrollTop(getRootScrollTop() - props.stickyOffsetTop); + } } emit('select', match.index); diff --git a/packages/vant/src/index-bar/test/__snapshots__/index.spec.jsx.snap b/packages/vant/src/index-bar/test/__snapshots__/index.spec.jsx.snap index 7635b1f60..c90509c59 100644 --- a/packages/vant/src/index-bar/test/__snapshots__/index.spec.jsx.snap +++ b/packages/vant/src/index-bar/test/__snapshots__/index.spec.jsx.snap @@ -6,6 +6,389 @@ exports[`should allow to custom anchor content 1`] = ` </div> `; +exports[`should render active anchor when stick prop is true and has stickyOffsetTop 1`] = ` +<div class="van-index-bar"> + <div class="van-index-bar__sidebar"> + <span + class="van-index-bar__index" + data-index="A" + > + A + </span> + <span + class="van-index-bar__index" + data-index="B" + > + B + </span> + <span + class="van-index-bar__index" + data-index="C" + > + C + </span> + <span + class="van-index-bar__index" + data-index="D" + > + D + </span> + <span + class="van-index-bar__index" + data-index="E" + > + E + </span> + <span + class="van-index-bar__index" + data-index="F" + > + F + </span> + <span + class="van-index-bar__index" + data-index="G" + > + G + </span> + <span + class="van-index-bar__index" + data-index="H" + > + H + </span> + <span + class="van-index-bar__index" + data-index="I" + > + I + </span> + <span + class="van-index-bar__index" + data-index="J" + > + J + </span> + <span + class="van-index-bar__index" + data-index="K" + > + K + </span> + <span + class="van-index-bar__index" + data-index="L" + > + L + </span> + <span + class="van-index-bar__index" + data-index="M" + > + M + </span> + <span + class="van-index-bar__index" + data-index="N" + > + N + </span> + <span + class="van-index-bar__index" + data-index="O" + > + O + </span> + <span + class="van-index-bar__index" + data-index="P" + > + P + </span> + <span + class="van-index-bar__index" + data-index="Q" + > + Q + </span> + <span + class="van-index-bar__index" + data-index="R" + > + R + </span> + <span + class="van-index-bar__index" + data-index="S" + > + S + </span> + <span + class="van-index-bar__index" + data-index="T" + > + T + </span> + <span + class="van-index-bar__index" + data-index="U" + > + U + </span> + <span + class="van-index-bar__index" + data-index="V" + > + V + </span> + <span + class="van-index-bar__index" + data-index="W" + > + W + </span> + <span + class="van-index-bar__index" + data-index="X" + > + X + </span> + <span + class="van-index-bar__index" + data-index="Y" + > + Y + </span> + <span + class="van-index-bar__index" + data-index="Z" + > + Z + </span> + </div> + <div data-index="0"> + <div class="van-index-anchor"> + A + </div> + </div> + <div style="height: 32px;"> + A1 + </div> + <div data-index="1"> + <div class="van-index-anchor"> + B + </div> + </div> + <div style="height: 32px;"> + B1 + </div> + <div data-index="2"> + <div class="van-index-anchor"> + C + </div> + </div> + <div style="height: 32px;"> + C1 + </div> +</div> +`; + +exports[`should render active anchor when stick prop is true and has stickyOffsetTop 2`] = ` +<div class="van-index-bar"> + <div class="van-index-bar__sidebar"> + <span + class="van-index-bar__index van-index-bar__index--active" + data-index="A" + > + A + </span> + <span + class="van-index-bar__index" + data-index="B" + > + B + </span> + <span + class="van-index-bar__index" + data-index="C" + > + C + </span> + <span + class="van-index-bar__index" + data-index="D" + > + D + </span> + <span + class="van-index-bar__index" + data-index="E" + > + E + </span> + <span + class="van-index-bar__index" + data-index="F" + > + F + </span> + <span + class="van-index-bar__index" + data-index="G" + > + G + </span> + <span + class="van-index-bar__index" + data-index="H" + > + H + </span> + <span + class="van-index-bar__index" + data-index="I" + > + I + </span> + <span + class="van-index-bar__index" + data-index="J" + > + J + </span> + <span + class="van-index-bar__index" + data-index="K" + > + K + </span> + <span + class="van-index-bar__index" + data-index="L" + > + L + </span> + <span + class="van-index-bar__index" + data-index="M" + > + M + </span> + <span + class="van-index-bar__index" + data-index="N" + > + N + </span> + <span + class="van-index-bar__index" + data-index="O" + > + O + </span> + <span + class="van-index-bar__index" + data-index="P" + > + P + </span> + <span + class="van-index-bar__index" + data-index="Q" + > + Q + </span> + <span + class="van-index-bar__index" + data-index="R" + > + R + </span> + <span + class="van-index-bar__index" + data-index="S" + > + S + </span> + <span + class="van-index-bar__index" + data-index="T" + > + T + </span> + <span + class="van-index-bar__index" + data-index="U" + > + U + </span> + <span + class="van-index-bar__index" + data-index="V" + > + V + </span> + <span + class="van-index-bar__index" + data-index="W" + > + W + </span> + <span + class="van-index-bar__index" + data-index="X" + > + X + </span> + <span + class="van-index-bar__index" + data-index="Y" + > + Y + </span> + <span + class="van-index-bar__index" + data-index="Z" + > + Z + </span> + </div> + <div + data-index="0" + style="height: 10px;" + > + <div + class="van-index-anchor van-index-anchor--sticky van-hairline--bottom" + style="transform: translate3d(0, 42px, 0);" + > + A + </div> + </div> + <div style="height: 32px;"> + A1 + </div> + <div data-index="1"> + <div class="van-index-anchor"> + B + </div> + </div> + <div style="height: 32px;"> + B1 + </div> + <div + data-index="2" + style + > + <div class="van-index-anchor"> + C + </div> + </div> + <div style="height: 32px;"> + C1 + </div> +</div> +`; + exports[`should update active anchor after page scroll 1`] = ` <div class="van-index-bar"> <div class="van-index-bar__sidebar"> diff --git a/packages/vant/src/index-bar/test/index.spec.jsx b/packages/vant/src/index-bar/test/index.spec.jsx index 8554e7df0..b48f17b6e 100644 --- a/packages/vant/src/index-bar/test/index.spec.jsx +++ b/packages/vant/src/index-bar/test/index.spec.jsx @@ -3,6 +3,7 @@ import { mount, trigger, triggerDrag, + mockScrollTo, mockScrollTop, mockScrollIntoView, } from '../../../test'; @@ -206,3 +207,48 @@ test('should render teleport prop correctly', () => { expect(root.querySelector('.van-index-bar__sidebar')).toBeTruthy(); }); + +test('should render active anchor when stick prop is true and has stickyOffsetTop', async () => { + const nativeRect = Element.prototype.getBoundingClientRect; + Element.prototype.getBoundingClientRect = function () { + const { index } = this.dataset; + return { + top: index ? index * (10 + 32) : 0, + height: 10, + }; + }; + + mockScrollTo(); + const onSelect = vi.fn(); + const onChange = vi.fn(); + + const wrapper = mount({ + render() { + return ( + <IndexBar onSelect={onSelect} stickyOffsetTop={42} onChange={onChange}> + <IndexAnchor index="A" data-index="0" /> + <div style={{ height: '32px' }}>A1</div> + <IndexAnchor index="B" data-index="1" /> + <div style={{ height: '32px' }}>B1</div> + <IndexAnchor index="C" data-index="2" /> + <div style={{ height: '32px' }}>C1</div> + </IndexBar> + ); + }, + }); + + await nextTick(); + expect(wrapper.html()).toMatchSnapshot(); + + const indexes = wrapper.findAll('.van-index-bar__index'); + await indexes[0].trigger('click'); + await trigger(window, 'scroll'); + + expect(wrapper.html()).toMatchSnapshot(); + expect(onSelect).toHaveBeenCalledWith('A'); + expect(onChange).toHaveBeenCalledWith('A'); + + wrapper.unmount(); + + Element.prototype.getBoundingClientRect = nativeRect; +}); diff --git a/packages/vant/test/dom.ts b/packages/vant/test/dom.ts index feb3e65d0..4337be427 100644 --- a/packages/vant/test/dom.ts +++ b/packages/vant/test/dom.ts @@ -37,6 +37,14 @@ function mockHTMLElementOffset() { }); } +export function mockScrollTo() { + const fn = vi.fn(); + if (inBrowser) { + window.scrollTo = fn; + } + return fn; +} + export function mockScrollIntoView() { const fn = vi.fn(); if (inBrowser) {