diff --git a/examples/sites/demos/apis/drawer.js b/examples/sites/demos/apis/drawer.js index ac687e0873..bb7232dd93 100644 --- a/examples/sites/demos/apis/drawer.js +++ b/examples/sites/demos/apis/drawer.js @@ -207,6 +207,20 @@ export default { mode: ['pc'], pcDemo: 'tips-props', hideSaas: true + }, + { + name: 'close-on-press-escape', + type: 'boolean', + defaultValue: 'false', + desc: { + 'zh-CN': 'ESC 键关闭抽屉', + 'en-US': 'ESC key to close drawer' + }, + mode: ['pc'], + pcDemo: 'closeOnPressEscape', + meta: { + stable: '3.28.0' + } } ], events: [ diff --git a/examples/sites/demos/pc/app/drawer/close-on-press-escape-composition-api.vue b/examples/sites/demos/pc/app/drawer/close-on-press-escape-composition-api.vue new file mode 100644 index 0000000000..dbcaedd7e3 --- /dev/null +++ b/examples/sites/demos/pc/app/drawer/close-on-press-escape-composition-api.vue @@ -0,0 +1,29 @@ + + + diff --git a/examples/sites/demos/pc/app/drawer/close-on-press-escape.spec.ts b/examples/sites/demos/pc/app/drawer/close-on-press-escape.spec.ts new file mode 100644 index 0000000000..2c91806dc7 --- /dev/null +++ b/examples/sites/demos/pc/app/drawer/close-on-press-escape.spec.ts @@ -0,0 +1,19 @@ +import { test, expect } from '@playwright/test' + +test('按 Esc 键关闭 Drawer(close-on-press-escape)', async ({ page }) => { + page.on('pageerror', (exception) => expect(exception).toBeNull()) + + await page.goto('drawer#close-on-press-escape') + + const drawer = page.locator('.tiny-drawer__main') + + // 打开 Drawer(用文本更稳定) + await page.getByText('抽屉组件').click() + await expect(drawer).toBeVisible() + + // 按 Esc + await page.keyboard.press('Escape') + + // Drawer 关闭 + await expect(drawer).toBeHidden() +}) diff --git a/examples/sites/demos/pc/app/drawer/close-on-press-escape.vue b/examples/sites/demos/pc/app/drawer/close-on-press-escape.vue new file mode 100644 index 0000000000..640c1c82f0 --- /dev/null +++ b/examples/sites/demos/pc/app/drawer/close-on-press-escape.vue @@ -0,0 +1,38 @@ + + + diff --git a/examples/sites/demos/pc/app/drawer/webdoc/drawer.js b/examples/sites/demos/pc/app/drawer/webdoc/drawer.js index 25a14d78ff..446969ced3 100644 --- a/examples/sites/demos/pc/app/drawer/webdoc/drawer.js +++ b/examples/sites/demos/pc/app/drawer/webdoc/drawer.js @@ -16,6 +16,18 @@ export default { }, codeFiles: ['basic-usage.vue'] }, + { + demoId: 'close-on-press-escape', + name: { + 'zh-CN': '按下 ESC 关闭抽屉', + 'en-US': '' + }, + desc: { + 'zh-CN': '

添加 close-on-press-escape 属性可以控制是否可以通过 ESC 关闭抽屉。

', + 'en-US': '' + }, + codeFiles: ['close-on-press-escape.vue'] + }, { demoId: 'use-through-method', name: { 'zh-CN': '通过方法调用', 'en-US': 'Use through method' }, diff --git a/packages/renderless/src/drawer/index.ts b/packages/renderless/src/drawer/index.ts index 48bcbf5ca6..b7a0e89b91 100644 --- a/packages/renderless/src/drawer/index.ts +++ b/packages/renderless/src/drawer/index.ts @@ -80,6 +80,36 @@ export const handleClose = } } +/* ================= Esc 关闭(受控) ================= */ +export const keydown = + ({ api, state, props }: Pick) => + (event: KeyboardEvent) => { + if (!state.visible) { + return + } + + if (!props.closeOnPressEscape) { + return + } + + if (event.key === 'Escape' || event.key === 'Esc') { + api.handleClose('esc', true) + } + } + +export const addKeydownEvent = + ({ api }: { api: IDrawerApi }) => + () => { + document.addEventListener('keydown', api.keydown) + } + +export const removeKeydownEvent = + ({ api }: { api: IDrawerApi }) => + () => { + document.removeEventListener('keydown', api.keydown) + } +/* ================================================== */ + export const mousedown = ({ state, vm }: { vm: ISharedRenderlessParamUtils['vm']; state: IDrawerState }) => (event) => { diff --git a/packages/renderless/src/drawer/vue.ts b/packages/renderless/src/drawer/vue.ts index ca457bfa3f..78974b043f 100644 --- a/packages/renderless/src/drawer/vue.ts +++ b/packages/renderless/src/drawer/vue.ts @@ -12,7 +12,10 @@ import { handleClose, computedWidth, computedHeight, - open + open, + keydown, + addKeydownEvent, + removeKeydownEvent } from './index' import type { IDrawerProps, @@ -50,8 +53,11 @@ export const renderless = ( mousedown: mousedown({ state, vm }), mousemove: mousemove({ state, props, emit }), mouseup: mouseup({ state }), - addDragEvent: addDragEvent({ api: api as IDrawerApi, vm }), - removeDragEvent: removeDragEvent({ api: api as IDrawerApi, vm }), + keydown: keydown({ api, state, props }), + addKeydownEvent: addKeydownEvent({ api }), + removeKeydownEvent: removeKeydownEvent({ api }), + addDragEvent: addDragEvent({ api, vm }), + removeDragEvent: removeDragEvent({ api, vm }), watchVisible: watchVisible({ state, api }), showScrollbar: showScrollbar(lockScrollClass), hideScrollbar: hideScrollbar(lockScrollClass), @@ -61,6 +67,7 @@ export const renderless = ( onMounted(() => { props.dragable && api.addDragEvent() + api.addKeydownEvent() if (props.lockScroll && props.visible) { api.showScrollbar() } @@ -68,6 +75,7 @@ export const renderless = ( onBeforeUnmount(() => { props.dragable && api.removeDragEvent() + api.removeKeydownEvent() props.lockScroll && api.hideScrollbar() }) diff --git a/packages/vue/src/drawer/src/pc.vue b/packages/vue/src/drawer/src/pc.vue index 909f116606..238449a1c7 100644 --- a/packages/vue/src/drawer/src/pc.vue +++ b/packages/vue/src/drawer/src/pc.vue @@ -161,7 +161,8 @@ export default defineComponent({ 'zIndex', 'beforeClose', 'tipsProps', - 'customSlots' + 'customSlots', + 'closeOnPressEscape' ], emits: ['update:visible', 'open', 'close', 'confirm', 'drag'], setup(props, context) {