Skip to content

Commit

Permalink
fix(cdk:scroll): virtual scroll scrolledBottom event
Browse files Browse the repository at this point in the history
scrolledBottom event shouldn't trigger when maxheight change
  • Loading branch information
sallerli1 committed Sep 22, 2022
1 parent 16c9df3 commit 185541f
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 31 deletions.
3 changes: 2 additions & 1 deletion packages/cdk/scroll/src/virtual/VirtualScroll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export default defineComponent({
heights,
)

const { syncScrollTop } = useScrollPlacement(
const { syncScrollTop, handleScroll } = useScrollPlacement(
props,
holderRef,
scrollTop,
Expand All @@ -66,6 +66,7 @@ export default defineComponent({
scrollHeight,
scrollOffset,
syncScrollTop,
handleScroll,
})

const scrollTo = useScrollTo(props, holderRef, getKey, heights, collectHeights, syncScrollTop)
Expand Down
36 changes: 19 additions & 17 deletions packages/cdk/scroll/src/virtual/composables/useScrollPlacement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@
*/

import type { VirtualScrollProps } from '../types'
import type { ComputedRef, Ref } from 'vue'
import type { Ref } from 'vue'

import { computed, watchEffect } from 'vue'
import { computed } from 'vue'

import { isFunction } from 'lodash-es'

import { callEmit } from '@idux/cdk/utils'

export type SyncScrollTop = (newTop: number | ((prev: number) => number)) => void
export type SyncScrollTop = (newTop: number | ((prev: number) => number), setHolderScrollTop?: boolean) => void

export interface ScrollPlacementContext {
scrolledTop: ComputedRef<boolean>
scrolledBottom: ComputedRef<boolean>
syncScrollTop: SyncScrollTop
handleScroll: (evt: Event) => void
}

const keepInRange = (maxScrollHeight: number, newScrollTop: number) => {
Expand All @@ -43,24 +42,27 @@ export function useScrollPlacement(
return height > 0 ? Math.max(height - containerHeight.value, 0) : NaN
})

const scrolledTop = computed(() => scrollTop.value <= 0)
const scrolledBottom = computed(() => scrollTop.value >= maxScrollHeight.value)

watchEffect(() => {
if (scrolledBottom.value) {
callEmit(props.onScrolledBottom)
}
})

const syncScrollTop = (newTop: number | ((prev: number) => number)) => {
const syncScrollTop = (newTop: number | ((prev: number) => number), setHolderScrollTop?: boolean) => {
const value = isFunction(newTop) ? newTop(scrollTop.value) : newTop
const alignedTop = keepInRange(maxScrollHeight.value, value)
const holderElement = holderRef.value
if (holderElement) {
if (holderElement && setHolderScrollTop) {
holderElement.scrollTop = alignedTop
}
changeScrollTop(alignedTop)
}

return { scrolledTop, scrolledBottom, syncScrollTop }
const handleScroll = (evt: Event) => {
const { scrollTop: newScrollTop } = evt.currentTarget as Element
if (newScrollTop !== scrollTop.value) {
syncScrollTop(newScrollTop)
}
callEmit(props.onScroll, evt)

if (newScrollTop >= maxScrollHeight.value) {
callEmit(props.onScrolledBottom)
}
}

return { syncScrollTop, handleScroll }
}
4 changes: 2 additions & 2 deletions packages/cdk/scroll/src/virtual/composables/useScrollTo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function useScrollTo(
const { dataSource, itemHeight } = props

if (typeof option === 'number') {
syncScrollTop(option)
syncScrollTop(option, true)
} else if (typeof option === 'object') {
const { align, offset = 0 } = option
let index: number
Expand Down Expand Up @@ -102,7 +102,7 @@ export function useScrollTo(
}

if (targetTop !== null && targetTop !== holderElement.scrollTop) {
syncScrollTop(targetTop)
syncScrollTop(targetTop, true)
}
}

Expand Down
12 changes: 1 addition & 11 deletions packages/cdk/scroll/src/virtual/contents/Holder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { type CSSProperties, computed, defineComponent, inject, onBeforeUnmount,
import { isString, throttle } from 'lodash-es'

import { offResize, onResize } from '@idux/cdk/resize'
import { callEmit } from '@idux/cdk/utils'

import { virtualScrollToken } from '../token'

Expand All @@ -24,8 +23,7 @@ export default defineComponent({
collectHeights,
scrollHeight,
scrollOffset,
scrollTop,
syncScrollTop,
handleScroll,
} = inject(virtualScrollToken)!

const style = computed<CSSProperties | undefined>(() => {
Expand Down Expand Up @@ -68,14 +66,6 @@ export default defineComponent({
}
})

const handleScroll = (evt: Event) => {
const { scrollTop: newScrollTop } = evt.currentTarget as Element
if (newScrollTop !== scrollTop.value) {
syncScrollTop(newScrollTop)
}
callEmit(props.onScroll, evt)
}

const contentRef = ref<HTMLDivElement>()
const onContentResize = throttle(collectHeights, 16)
// 这里不能用 useResizeObserver, 会有 test 爆栈警告, 具体原因后面再排查。
Expand Down
1 change: 1 addition & 0 deletions packages/cdk/scroll/src/virtual/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export interface VirtualScrollContext {
scrollHeight: Ref<number>
scrollOffset: Ref<number | undefined>
syncScrollTop: SyncScrollTop
handleScroll: (evt: Event) => void
}

export const virtualScrollToken: InjectionKey<VirtualScrollContext> = Symbol('virtualScrollToken')

0 comments on commit 185541f

Please sign in to comment.