diff --git a/docs/en-US/component/drawer.md b/docs/en-US/component/drawer.md
index 178aaef27b..4b374bebb6 100644
--- a/docs/en-US/component/drawer.md
+++ b/docs/en-US/component/drawer.md
@@ -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
diff --git a/packages/components/drawer/__tests__/drawer.test.ts b/packages/components/drawer/__tests__/drawer.test.ts
index 6d0b70c062..2b8992f8cb 100644
--- a/packages/components/drawer/__tests__/drawer.test.ts
+++ b/packages/components/drawer/__tests__/drawer.test.ts
@@ -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(
+ `
+
+ ${content}
+
+ `,
+ () => ({
+ 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', () => {
diff --git a/packages/components/drawer/src/composables/useResizable.ts b/packages/components/drawer/src/composables/useResizable.ts
index ef344847ab..dcd802a570 100644
--- a/packages/components/drawer/src/composables/useResizable.ts
+++ b/packages/components/drawer/src/composables/useResizable.ts
@@ -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
+ target: Ref,
+ emit: SetupContext['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)
diff --git a/packages/components/drawer/src/drawer.ts b/packages/components/drawer/src/drawer.ts
index 77198bea21..2ba02c7bde 100644
--- a/packages/components/drawer/src/drawer.ts
+++ b/packages/components/drawer/src/drawer.ts
@@ -32,4 +32,14 @@ export const drawerProps = buildProps({
export type DrawerProps = ExtractPropTypes
export type DrawerPropsPublic = __ExtractPublicPropTypes
-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
diff --git a/packages/components/drawer/src/drawer.vue b/packages/components/drawer/src/drawer.vue
index 985c9823b6..6c6207b9e2 100644
--- a/packages/components/drawer/src/drawer.vue
+++ b/packages/components/drawer/src/drawer.vue
@@ -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)