fix(Sticky): resize or orientationchange wrapper no reset width and height (#11753)

* fix(Swipe): props changed but component didn't

* fix(Swipe): target watch windowWidth

* Update packages/vant/src/swipe/Swipe.tsx

* fix(Sticky): resize or orientationchange wrapper no reset width and height

* fix(Sticky): resize or orientationchange wrapper no reset width and height

* fix(Sticky): resize or orientationchange wrapper no reset width and height

* fix(Sticky): resize or orientationchange wrapper no reset width and height

---------

Co-authored-by: neverland <jait.chen@foxmail.com>
This commit is contained in:
Zhousg 2023-04-26 19:40:25 +08:00 committed by GitHub
parent 5338367ea3
commit 68d1ade239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 3 deletions

View File

@ -7,6 +7,7 @@ import {
type PropType, type PropType,
type CSSProperties, type CSSProperties,
type ExtractPropTypes, type ExtractPropTypes,
nextTick,
} from 'vue'; } from 'vue';
// Utils // Utils
@ -20,6 +21,8 @@ import {
makeStringProp, makeStringProp,
makeNumericProp, makeNumericProp,
createNamespace, createNamespace,
windowWidth,
windowHeight,
} from '../utils'; } from '../utils';
// Composables // Composables
@ -56,12 +59,16 @@ export default defineComponent({
height: 0, // root height height: 0, // root height
transform: 0, transform: 0,
}); });
const isReset = ref(false);
const offset = computed(() => const offset = computed(() =>
unitToPx(props.position === 'top' ? props.offsetTop : props.offsetBottom) unitToPx(props.position === 'top' ? props.offsetTop : props.offsetBottom)
); );
const rootStyle = computed<CSSProperties | undefined>(() => { const rootStyle = computed<CSSProperties | undefined>(() => {
if (isReset.value) {
return;
}
const { fixed, height, width } = state; const { fixed, height, width } = state;
if (fixed) { if (fixed) {
return { return {
@ -72,7 +79,7 @@ export default defineComponent({
}); });
const stickyStyle = computed<CSSProperties | undefined>(() => { const stickyStyle = computed<CSSProperties | undefined>(() => {
if (!state.fixed) { if (!state.fixed || isReset.value) {
return; return;
} }
@ -146,9 +153,25 @@ export default defineComponent({
}); });
useVisibilityChange(root, onScroll); useVisibilityChange(root, onScroll);
watch([windowWidth, windowHeight], () => {
if (!root.value || isHidden(root) || !state.fixed) {
return;
}
isReset.value = true;
nextTick(() => {
const rootRect = useRect(root);
state.width = rootRect.width;
state.height = rootRect.height;
isReset.value = false;
});
});
return () => ( return () => (
<div ref={root} style={rootStyle.value}> <div ref={root} style={rootStyle.value}>
<div class={bem({ fixed: state.fixed })} style={stickyStyle.value}> <div
class={bem({ fixed: state.fixed && !isReset.value })}
style={stickyStyle.value}
>
{slots.default?.()} {slots.default?.()}
</div> </div>
</div> </div>

View File

@ -82,6 +82,34 @@ exports[`should sticky inside container when using container prop 2`] = `
</div> </div>
`; `;
exports[`should sticky resize or orientationchange reset root height and width 1`] = `
<div style="width: 375px; height: 20px;">
<div class="van-sticky van-sticky--fixed"
style="width: 375px; height: 20px; top: 0px;"
>
<div class="content"
style="height: 20px;"
>
Content
</div>
</div>
</div>
`;
exports[`should sticky resize or orientationchange reset root height and width 2`] = `
<div style="width: 677px; height: 20px;">
<div class="van-sticky van-sticky--fixed"
style="width: 677px; height: 20px; top: 0px;"
>
<div class="content"
style="height: 20px;"
>
Content
</div>
</div>
</div>
`;
exports[`should sticky to bottom after scrolling 1`] = ` exports[`should sticky to bottom after scrolling 1`] = `
<div style="height: 10px;"> <div style="height: 10px;">
<div class="van-sticky van-sticky--fixed" <div class="van-sticky van-sticky--fixed"

View File

@ -1,5 +1,5 @@
import { nextTick, ref } from 'vue'; import { nextTick, ref } from 'vue';
import { VueWrapper } from '@vue/test-utils'; import { VueWrapper, flushPromises } from '@vue/test-utils';
import { mockScrollTop, trigger, mount } from '../../../test'; import { mockScrollTop, trigger, mount } from '../../../test';
import { Sticky } from '..'; import { Sticky } from '..';
import { ComponentInstance } from '../../utils'; import { ComponentInstance } from '../../utils';
@ -353,3 +353,41 @@ test('should emit change event when sticky status changed', async () => {
restore(); restore();
}); });
test('should sticky resize or orientationchange reset root height and width', async () => {
const wrapper = mount({
render() {
return (
<Sticky>
<div class="content" style="height:20px">
Content
</div>
</Sticky>
);
},
});
window.innerWidth = 375;
const mockStickyRect = jest
.spyOn(wrapper.element, 'getBoundingClientRect')
.mockReturnValue({
top: -100,
bottom: -90,
width: window.innerWidth,
height: 20,
} as DOMRect);
await mockScrollTop(100);
expect(wrapper.html()).toMatchSnapshot();
window.innerWidth = 677;
mockStickyRect.mockReturnValue({
width: window.innerWidth,
height: 20,
} as DOMRect);
await trigger(window, 'resize');
await flushPromises();
expect(wrapper.html()).toMatchSnapshot();
mockStickyRect.mockRestore();
});