mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
feat(components): [drawer] add resize-start resize resize-end emits (#22784)
* feat(components): [drawer] add emits * chore: update * chore: update
This commit is contained in:
@@ -137,14 +137,17 @@ Drawer provides an API called `destroy-on-close`, which is a flag variable that
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Description | Type |
|
||||
| ---------------- | ------------------------------------------------ | ----------------------- |
|
||||
| open | Triggered before Drawer opening animation begins | ^[Function]`() => void` |
|
||||
| opened | Triggered after Drawer opening animation ended | ^[Function]`() => void` |
|
||||
| close | Triggered before Drawer closing animation begins | ^[Function]`() => void` |
|
||||
| closed | Triggered after Drawer closing animation ended | ^[Function]`() => void` |
|
||||
| open-auto-focus | triggers after Drawer opens and content focused | ^[Function]`() => void` |
|
||||
| close-auto-focus | triggers after Drawer closed and content focused | ^[Function]`() => void` |
|
||||
| Name | Description | Type |
|
||||
| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------ |
|
||||
| open | Triggered before Drawer opening animation begins | ^[Function]`() => void` |
|
||||
| opened | Triggered after Drawer opening animation ended | ^[Function]`() => void` |
|
||||
| close | Triggered before Drawer closing animation begins | ^[Function]`() => void` |
|
||||
| closed | Triggered after Drawer closing animation ended | ^[Function]`() => void` |
|
||||
| open-auto-focus | triggers after Drawer opens and content focused | ^[Function]`() => void` |
|
||||
| close-auto-focus | triggers after Drawer closed and content focused | ^[Function]`() => void` |
|
||||
| resize-start ^(2.11.8) | Triggered when resizing starts (when `resizable` is enabled) | ^[Function]`(event: MouseEvent, size: number) => void` |
|
||||
| resize ^(2.11.8) | Triggered while resizing (when `resizable` is enabled) | ^[Function]`(event: MouseEvent, size: number) => void` |
|
||||
| resize-end ^(2.11.8) | Triggered when resizing ends (when `resizable` is enabled) | ^[Function]`(event: MouseEvent, size: number) => void` |
|
||||
|
||||
### Slots
|
||||
|
||||
|
||||
@@ -581,6 +581,100 @@ describe('Drawer', () => {
|
||||
|
||||
cleanup()
|
||||
})
|
||||
|
||||
test('should emit resize-start, resize and resize-end events', async () => {
|
||||
const cleanup = defineGetter(window, 'innerWidth', '100')
|
||||
const onResizeStart = vi.fn()
|
||||
const onResize = vi.fn()
|
||||
const onResizeEnd = vi.fn()
|
||||
|
||||
const wrapper = _mount(
|
||||
`
|
||||
<el-drawer
|
||||
v-model='visible'
|
||||
direction='ltr'
|
||||
resizable
|
||||
size='50%'
|
||||
@resize-start="onResizeStart"
|
||||
@resize="onResize"
|
||||
@resize-end="onResizeEnd">
|
||||
<span>${content}</span>
|
||||
</el-drawer>
|
||||
`,
|
||||
() => ({
|
||||
visible: true,
|
||||
}),
|
||||
{
|
||||
methods: {
|
||||
onResizeStart,
|
||||
onResize,
|
||||
onResizeEnd,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
await nextTick()
|
||||
|
||||
const dragger = wrapper.find('.el-drawer__dragger')
|
||||
const drawerEl = wrapper.find('.el-drawer').element as HTMLDivElement
|
||||
Object.defineProperty(drawerEl, 'offsetWidth', {
|
||||
value: 50,
|
||||
configurable: true,
|
||||
})
|
||||
|
||||
const prop = 'pageX'
|
||||
|
||||
// Simulate mouse down - should trigger resize-start
|
||||
const mousedown = new MouseEvent('mousedown', { bubbles: true })
|
||||
const mousedownCleanup = defineGetter(mousedown, prop, 50)
|
||||
dragger.element.dispatchEvent(mousedown)
|
||||
await nextTick()
|
||||
|
||||
expect(onResizeStart).toHaveBeenCalledTimes(1)
|
||||
expect(onResizeStart).toHaveBeenCalledWith(
|
||||
expect.any(MouseEvent),
|
||||
expect.any(Number)
|
||||
)
|
||||
|
||||
// Simulate mouse move - should trigger resize
|
||||
const mousemove = new MouseEvent('mousemove', { bubbles: true })
|
||||
const mousemoveCleanup = defineGetter(mousemove, prop, 80)
|
||||
window.dispatchEvent(mousemove)
|
||||
await nextTick()
|
||||
|
||||
expect(onResize).toHaveBeenCalled()
|
||||
expect(onResize).toHaveBeenCalledWith(
|
||||
expect.any(MouseEvent),
|
||||
expect.any(Number)
|
||||
)
|
||||
const resizeCallCount = onResize.mock.calls.length
|
||||
|
||||
// Simulate another mouse move
|
||||
const mousemove2 = new MouseEvent('mousemove', { bubbles: true })
|
||||
const mousemove2Cleanup = defineGetter(mousemove2, prop, 100)
|
||||
window.dispatchEvent(mousemove2)
|
||||
await nextTick()
|
||||
|
||||
expect(onResize).toHaveBeenCalledTimes(resizeCallCount + 1)
|
||||
|
||||
// Simulate mouse up - should trigger resize-end
|
||||
const mouseup = new MouseEvent('mouseup', { bubbles: true })
|
||||
const mouseupCleanup = defineGetter(mouseup, prop, 100)
|
||||
window.dispatchEvent(mouseup)
|
||||
await nextTick()
|
||||
|
||||
expect(onResizeEnd).toHaveBeenCalledTimes(1)
|
||||
expect(onResizeEnd).toHaveBeenCalledWith(
|
||||
expect.any(MouseEvent),
|
||||
expect.any(Number)
|
||||
)
|
||||
|
||||
mousedownCleanup()
|
||||
mousemoveCleanup()
|
||||
mousemove2Cleanup()
|
||||
mouseupCleanup()
|
||||
cleanup()
|
||||
})
|
||||
})
|
||||
|
||||
describe('accessibility', () => {
|
||||
|
||||
@@ -2,12 +2,13 @@ import { computed, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import { addUnit } from '@element-plus/utils'
|
||||
import { clamp, useEventListener, useWindowSize } from '@vueuse/core'
|
||||
|
||||
import type { Ref } from 'vue'
|
||||
import type { DrawerProps } from '../drawer'
|
||||
import type { Ref, SetupContext } from 'vue'
|
||||
import type { DrawerEmits, DrawerProps } from '../drawer'
|
||||
|
||||
export function useResizable(
|
||||
props: DrawerProps,
|
||||
target: Ref<HTMLElement | undefined>
|
||||
target: Ref<HTMLElement | undefined>,
|
||||
emit: SetupContext<DrawerEmits>['emit']
|
||||
) {
|
||||
const { width, height } = useWindowSize()
|
||||
|
||||
@@ -61,6 +62,7 @@ export function useResizable(
|
||||
|
||||
startPos = [e.pageX, e.pageY]
|
||||
isResizing.value = true
|
||||
emit('resize-start', e, startSize.value)
|
||||
cleanups.push(
|
||||
useEventListener(window, 'mouseup', onMouseUp),
|
||||
useEventListener(window, 'mousemove', onMouseMove)
|
||||
@@ -72,15 +74,23 @@ export function useResizable(
|
||||
const offsetX = pageX - startPos[0]
|
||||
const offsetY = pageY - startPos[1]
|
||||
offset.value = isHorizontal.value ? offsetX : offsetY
|
||||
emit('resize', e, getSize.value)
|
||||
}
|
||||
|
||||
const onMouseUp = () => {
|
||||
const onMouseUp = (e?: MouseEvent) => {
|
||||
// premature interruption
|
||||
// avoid triggering meaningless execution due to watch size/resizable constraints.
|
||||
if (!isResizing.value) return
|
||||
|
||||
startPos = []
|
||||
startSize.value = getSize.value
|
||||
offset.value = 0
|
||||
isResizing.value = false
|
||||
cleanups.forEach((cleanup) => cleanup?.())
|
||||
cleanups = []
|
||||
if (e) {
|
||||
emit('resize-end', e, startSize.value)
|
||||
}
|
||||
}
|
||||
|
||||
const cleanup = useEventListener(target, 'mousedown', onMousedown)
|
||||
|
||||
@@ -32,4 +32,14 @@ export const drawerProps = buildProps({
|
||||
export type DrawerProps = ExtractPropTypes<typeof drawerProps>
|
||||
export type DrawerPropsPublic = __ExtractPublicPropTypes<typeof drawerProps>
|
||||
|
||||
export const drawerEmits = dialogEmits
|
||||
export const drawerEmits = {
|
||||
...dialogEmits,
|
||||
'resize-start': (event: MouseEvent, size: number) =>
|
||||
event instanceof MouseEvent && typeof size === 'number',
|
||||
resize: (event: MouseEvent, size: number) =>
|
||||
event instanceof MouseEvent && typeof size === 'number',
|
||||
'resize-end': (event: MouseEvent, size: number) =>
|
||||
event instanceof MouseEvent && typeof size === 'number',
|
||||
}
|
||||
|
||||
export type DrawerEmits = typeof drawerEmits
|
||||
|
||||
@@ -123,7 +123,7 @@ defineOptions({
|
||||
})
|
||||
|
||||
const props = defineProps(drawerProps)
|
||||
defineEmits(drawerEmits)
|
||||
const emit = defineEmits(drawerEmits)
|
||||
const slots = useSlots()
|
||||
|
||||
useDeprecated(
|
||||
@@ -160,7 +160,7 @@ const {
|
||||
handleClose,
|
||||
} = useDialog(props, drawerRef)
|
||||
|
||||
const { isHorizontal, size, isResizing } = useResizable(props, draggerRef)
|
||||
const { isHorizontal, size, isResizing } = useResizable(props, draggerRef, emit)
|
||||
|
||||
const penetrable = computed(() => props.modalPenetrable && !props.modal)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user