Skip to content

Commit

Permalink
fix(directives): [repeat-click] Interval time is too short for single…
Browse files Browse the repository at this point in the history
… clicks (#9466)

* fix(directives): [repeat-click] time is too short for single clicks

* fix(test-utils): [repeat-click] increase sleep time

Updated times according to PR #9466

* fix(test-utils): [repeat-click] increase test time

Updated times according to PR #9466

* chore: update

* chore: improve test case

Co-authored-by: holazz <2418184580@qq.com>
  • Loading branch information
opuu and holazz committed Aug 31, 2022
1 parent fa312f0 commit e25df54
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 39 deletions.
40 changes: 14 additions & 26 deletions packages/directives/__tests__/repeat-click.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import sleep from '@element-plus/test-utils/sleep'
import RepeatClick from '../repeat-click'
import RepeatClick, { REPEAT_DELAY, REPEAT_INTERVAL } from '../repeat-click'

const PRESS_TIME = REPEAT_DELAY + REPEAT_INTERVAL
let handler: ReturnType<typeof vi.fn>

const _mount = () =>
Expand All @@ -27,40 +27,28 @@ const _mount = () =>
)

describe('Directives.vue', () => {
it('click test', async () => {
it('single click', async () => {
const wrapper = _mount()
const block = wrapper.find('#block')

vi.useFakeTimers()
block.trigger('mousedown')
await sleep(330)
vi.advanceTimersByTime(PRESS_TIME - 1)
document.dispatchEvent(new MouseEvent('mouseup'))

expect(handler).toHaveBeenCalledTimes(3)
expect(handler).toHaveBeenCalledTimes(1)
vi.useRealTimers()
})

it('time interval between mousedown and mouseup is slightly less than 100ms', async () => {
it('click and hold on', async () => {
const wrapper = _mount()
const block = wrapper.find('#block')

for (let i = 0; i < 10; i++) {
block.trigger('mousedown')
await sleep(99)
document.dispatchEvent(new MouseEvent('mouseup'))
}

expect(handler).toHaveBeenCalledTimes(10)
})

it('time interval between mousedown and mouseup is slightly more than 100ms', async () => {
const wrapper = _mount()
const block = wrapper.find('#block')

for (let i = 0; i < 10; i++) {
block.trigger('mousedown')
await sleep(101)
document.dispatchEvent(new MouseEvent('mouseup'))
}
vi.useFakeTimers()
block.trigger('mousedown')
vi.advanceTimersByTime(PRESS_TIME)
document.dispatchEvent(new MouseEvent('mouseup'))

expect(handler).toHaveBeenCalledTimes(10)
expect(handler).toHaveBeenCalledTimes(2)
vi.useRealTimers()
})
})
31 changes: 18 additions & 13 deletions packages/directives/repeat-click/index.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
import type { DirectiveBinding, ObjectDirective } from 'vue'

export const REPEAT_INTERVAL = 100
export const REPEAT_DELAY = 600

const RepeatClick: ObjectDirective = {
beforeMount(el: HTMLElement, binding: DirectiveBinding) {
let interval: ReturnType<typeof setInterval> | null = null
let isHandlerCalled = false
let delay: ReturnType<typeof setTimeout> | null = null

const handler = () => binding.value && binding.value()

const clear = () => {
clearInterval(interval!)
interval = null

if (!isHandlerCalled) {
handler()
if (delay) {
clearTimeout(delay)
delay = null
}
if (interval) {
clearInterval(interval)
interval = null
}
isHandlerCalled = false
}

el.addEventListener('mousedown', (e: MouseEvent) => {
if (e.button !== 0) return
handler()

document.addEventListener('mouseup', clear, { once: true })

clearInterval(interval!)
interval = setInterval(() => {
isHandlerCalled = true
handler()
}, 100)
clear()
delay = setTimeout(() => {
interval = setInterval(() => {
handler()
}, REPEAT_INTERVAL)
}, REPEAT_DELAY)
})
},
}
Expand Down

0 comments on commit e25df54

Please sign in to comment.