Skip to content

Commit

Permalink
feat(ui/picker): support scroll while click the option and refactor c…
Browse files Browse the repository at this point in the history
…ode (#1039)
  • Loading branch information
gaoting authored May 17, 2023
1 parent 1d3efe4 commit 59a8d4c
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 33 deletions.
82 changes: 50 additions & 32 deletions packages/varlet-ui/src/picker/Picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@
}"
@transitionend="handleTransitionend(c)"
>
<div :class="n('option')" :style="{ height: `${optionHeight}px` }" v-for="t in c.column.texts" :key="t">
<div
:class="n('option')"
:style="{ height: `${optionHeight}px` }"
v-for="(t, i) in c.column.texts"
:key="t"
@click="handleClick(c, i)"
>
<div :class="n('text')">{{ textFormatter(t, c.columnIndex) }}</div>
</div>
</div>
Expand All @@ -90,11 +96,11 @@
<script lang="ts">
import VarButton from '../button'
import VarPopup from '../popup'
import { defineComponent, watch, ref, computed, Transition, toRaw } from 'vue'
import { defineComponent, watch, ref, computed, Transition, toRaw, TransitionGroup } from 'vue'
import { props } from './props'
import { isArray } from '@varlet/shared'
import { dt } from '../utils/shared'
import { toPxNum, getTranslate } from '../utils/elements'
import { toPxNum, getTranslateY } from '../utils/elements'
import { pack } from '../locale'
import type { Ref, ComputedRef, ComponentPublicInstance } from 'vue'
import type { CascadeColumn, NormalColumn } from './props'
Expand All @@ -117,10 +123,17 @@ export interface ScrollColumn {
scrollEl: HTMLElement | null
}
export interface ScrollToOptions {
duration?: number
emitChange?: boolean
}
const { n, classes } = createNamespace('picker')
const MOMENTUM_RECORD_TIME = 300
const MOMENTUM_ALLOW_DISTANCE = 15
const TRANSITION_DURATION = 200
const MOMENTUM_TRANSITION_DURATION = 1000
let sid = 0
Expand Down Expand Up @@ -150,15 +163,15 @@ export default defineComponent({
call(props['onUpdate:show'], value)
}
const limitTranslate = (scrollColumn: ScrollColumn) => {
const START_LIMIT = optionHeight.value + center.value
const END_LIMIT = center.value - scrollColumn.column.texts.length * optionHeight.value
const boundaryTranslate = (scrollColumn: ScrollColumn) => {
const startTranslate = optionHeight.value + center.value
const endTranslate = center.value - scrollColumn.column.texts.length * optionHeight.value
if (scrollColumn.translate >= START_LIMIT) {
scrollColumn.translate = START_LIMIT
if (scrollColumn.translate >= startTranslate) {
scrollColumn.translate = startTranslate
}
if (scrollColumn.translate <= END_LIMIT) {
scrollColumn.translate = END_LIMIT
if (scrollColumn.translate <= endTranslate) {
scrollColumn.translate = endTranslate
}
}
Expand All @@ -171,7 +184,7 @@ export default defineComponent({
return index
}
const getIndex = (scrollColumn: ScrollColumn) => {
const getViewIndex = (scrollColumn: ScrollColumn) => {
const index = Math.round((center.value - scrollColumn.translate) / optionHeight.value)
return boundaryIndex(scrollColumn, index)
Expand All @@ -187,16 +200,13 @@ export default defineComponent({
}
}
const scrollTo = (scrollColumn: ScrollColumn, index: number, duration: number, noEmit = false) => {
const translate = center.value - boundaryIndex(scrollColumn, index) * optionHeight.value
if (translate === scrollColumn.translate) {
scrollColumn.scrolling = false
!noEmit && change(scrollColumn)
}
const scrollTo = (scrollColumn: ScrollColumn, options: ScrollToOptions = {}) => {
const { duration = 0, emitChange = false } = options
const translate = center.value - boundaryIndex(scrollColumn, scrollColumn.index) * optionHeight.value
scrollColumn.translate = translate
scrollColumn.duration = duration
emitChange && change(scrollColumn)
}
const momentum = (scrollColumn: ScrollColumn, distance: number, duration: number) => {
Expand All @@ -207,7 +217,7 @@ export default defineComponent({
scrollColumn.touching = true
scrollColumn.scrolling = false
scrollColumn.duration = 0
scrollColumn.translate = getTranslate(scrollColumn.scrollEl as HTMLElement)
scrollColumn.translate = getTranslateY(scrollColumn.scrollEl as HTMLElement)
}
const handleTouchmove = (event: TouchEvent, scrollColumn: ScrollColumn) => {
Expand All @@ -216,11 +226,11 @@ export default defineComponent({
}
const { clientY } = event.touches[0]
const moveY = scrollColumn.prevY !== undefined ? clientY - scrollColumn.prevY : 0
const deltaY = scrollColumn.prevY !== undefined ? clientY - scrollColumn.prevY : 0
scrollColumn.prevY = clientY
scrollColumn.translate += moveY
scrollColumn.translate += deltaY
limitTranslate(scrollColumn)
boundaryTranslate(scrollColumn)
const now = performance.now()
if (now - scrollColumn.momentumTime > MOMENTUM_RECORD_TIME) {
Expand All @@ -229,6 +239,12 @@ export default defineComponent({
}
}
const handleClick = (scrollColumn: ScrollColumn, index: number) => {
console.log('11111111', scrollColumn, index)
scrollColumn.index = index
scrollTo(scrollColumn, { duration: TRANSITION_DURATION, emitChange: true })
}
const handleTouchend = (event: TouchEvent, scrollColumn: ScrollColumn) => {
scrollColumn.touching = false
scrollColumn.scrolling = true
Expand All @@ -239,8 +255,8 @@ export default defineComponent({
shouldMomentum && momentum(scrollColumn, distance, duration)
scrollColumn.index = getIndex(scrollColumn)
scrollTo(scrollColumn, scrollColumn.index, shouldMomentum ? 1000 : 200)
scrollColumn.index = getViewIndex(scrollColumn)
scrollTo(scrollColumn, { duration: shouldMomentum ? MOMENTUM_TRANSITION_DURATION : TRANSITION_DURATION })
}
const handleTransitionend = (scrollColumn: ScrollColumn) => {
Expand All @@ -265,7 +281,7 @@ export default defineComponent({
scrollEl: null,
scrolling: false,
}
scrollTo(scrollColumn, scrollColumn.index, 0, true)
scrollTo(scrollColumn)
return scrollColumn
})
}
Expand Down Expand Up @@ -306,7 +322,7 @@ export default defineComponent({
}
scrollColumns.push(scrollColumn)
scrollTo(scrollColumn, scrollColumn.index, 0, true)
scrollTo(scrollColumn)
createChildren(
scrollColumns,
(scrollColumn.columns as CascadeColumn[])[scrollColumn.index].children,
Expand Down Expand Up @@ -342,24 +358,25 @@ export default defineComponent({
}
prevIndexes = [...indexes]
console.log('333', texts, indexes)
call(onChange, texts, indexes)
}
const stopScroll = () => {
if (props.cascade) {
const currentScrollColumn = scrollColumns.value.find((scrollColumn) => scrollColumn.scrolling)
if (currentScrollColumn) {
currentScrollColumn.translate = getTranslate(currentScrollColumn.scrollEl as HTMLElement)
currentScrollColumn.index = getIndex(currentScrollColumn)
scrollTo(currentScrollColumn, currentScrollColumn.index, 0, true)
currentScrollColumn.translate = getTranslateY(currentScrollColumn.scrollEl as HTMLElement)
currentScrollColumn.index = getViewIndex(currentScrollColumn)
scrollTo(currentScrollColumn)
currentScrollColumn.scrolling = false
rebuildChildren(currentScrollColumn)
}
} else {
scrollColumns.value.forEach((scrollColumn) => {
scrollColumn.translate = getTranslate(scrollColumn.scrollEl as HTMLElement)
scrollColumn.index = getIndex(scrollColumn)
scrollTo(scrollColumn, scrollColumn.index, 0)
scrollColumn.translate = getTranslateY(scrollColumn.scrollEl as HTMLElement)
scrollColumn.index = getViewIndex(scrollColumn)
scrollTo(scrollColumn)
})
}
}
Expand Down Expand Up @@ -417,6 +434,7 @@ export default defineComponent({
confirm,
cancel,
dt,
handleClick,
}
},
})
Expand Down
23 changes: 23 additions & 0 deletions packages/varlet-ui/src/picker/__tests__/component.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,29 @@ test('test scroll up & onConfirm', async () => {
wrapper.unmount()
})

test('test click & onConfirm', async () => {
const { mockRestore } = mockTranslate()
const onChange = jest.fn()

const wrapper = mount(VarPicker, {
props: {
columns: [['A', 'B', 'C']],
onChange,
},
})

const options = wrapper.findAll('.var-picker__option')
expect(options.length).toBe(3)

await options[1].trigger('click')
await delay(300)

expect(onChange).toHaveBeenLastCalledWith(['B'], [1])

mockRestore()
wrapper.unmount()
})

test('test scroll down & onCancel', async () => {
const { mockRestore } = mockTranslate()
const onCancel = jest.fn()
Expand Down
2 changes: 1 addition & 1 deletion packages/varlet-ui/src/utils/elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export function inViewport(element: HTMLElement): boolean {
return xInViewport && yInViewport
}

export function getTranslate(el: HTMLElement) {
export function getTranslateY(el: HTMLElement) {
const { transform } = getStyle(el)
return +transform.slice(transform.lastIndexOf(',') + 2, transform.length - 1)
}
Expand Down

0 comments on commit 59a8d4c

Please sign in to comment.