Skip to content

Commit

Permalink
feat: Drawer 和 Modal 添加 Esc 快捷关闭配置项 (#680)
Browse files Browse the repository at this point in the history
Co-authored-by: blankzhang <[email protected]>
  • Loading branch information
zym19960704 and blankzhang authored Mar 20, 2024
1 parent 3b919b4 commit 72ca443
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 35 deletions.
22 changes: 17 additions & 5 deletions components/_util/use/useEsc.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { isRef, onBeforeUnmount, onMounted, watch, type Ref } from 'vue';
import { isRef, onBeforeUnmount, watch, ref, type Ref } from 'vue';

export default function useEsc(
action: (event: KeyboardEvent) => void,
escClosable: Ref<boolean> = ref(true),
open?: Ref<boolean>,
) {
const onGlobalKeyDown = (event: KeyboardEvent) => {
Expand All @@ -14,16 +15,27 @@ export default function useEsc(
if (isRef(open)) {
watch(open, () => {
if (open.value) {
window.addEventListener('keydown', onGlobalKeyDown);
escClosable.value &&
window.addEventListener('keydown', onGlobalKeyDown);
} else {
window.removeEventListener('keydown', onGlobalKeyDown);
}
});
}

onMounted(() => {
window.addEventListener('keydown', onGlobalKeyDown);
});
watch(
escClosable,
() => {
if (escClosable.value) {
window.addEventListener('keydown', onGlobalKeyDown);
} else {
window.removeEventListener('keydown', onGlobalKeyDown);
}
},
{
immediate: true,
},
);

onBeforeUnmount(() => {
window.removeEventListener('keydown', onGlobalKeyDown);
Expand Down
7 changes: 6 additions & 1 deletion components/drawer/drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import useLockScreen from '../_util/use/useLockScreen';
import { useConfig } from '../config-provider';
import { useTheme } from '../_theme/useTheme';
import { pxfy } from '../_util/utils';
import useEsc from '../_util/use/useEsc';
import { useResizable } from './useResizable';
import { COMPONENT_NAME, prefixCls } from './const';
import {
Expand Down Expand Up @@ -53,11 +54,15 @@ const Drawer = defineComponent({
() => props.getContainer || config.getContainer?.value,
);

function handleCancel(event: MouseEvent) {
function handleCancel(event: MouseEvent | KeyboardEvent) {
ctx.emit(UPDATE_SHOW_EVENT, false);
ctx.emit(CANCEL_EVENT, event);
}

const escClosable = computed(() => props.escClosable);

useEsc(handleCancel, escClosable);

function handleOk(event: MouseEvent) {
ctx.emit(OK_EVENT, event);
}
Expand Down
4 changes: 4 additions & 0 deletions components/drawer/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const drawerProps = {
type: Boolean,
default: true,
},
escClosable: {
type: Boolean,
default: true,
},
// 没有遮罩层,页面其他交互是否可操作
operable: {
type: Boolean,
Expand Down
4 changes: 3 additions & 1 deletion components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ const Modal = defineComponent({
ctx.emit(CANCEL_EVENT, event);
}

useEsc(handleCancel);
const escClosable = computed(() => props.escClosable);

useEsc(handleCancel, escClosable);

function handleOk(event: MouseEvent) {
ctx.emit(OK_EVENT, event);
Expand Down
4 changes: 4 additions & 0 deletions components/modal/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export const modalProps = {
type: Boolean,
default: true,
},
escClosable: {
type: Boolean,
default: true,
},
type: {
type: String as PropType<ModalType>,
},
Expand Down
48 changes: 48 additions & 0 deletions docs/.vitepress/components/drawer/closable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<FSpace>
<FForm :labelWidth="100">
<FFormItem label="点击蒙层关闭:">
<FRadioGroup
v-model="maskClosable"
:options="[
{ label: '是(默认)', value: true },
{ label: '否', value: false },
]"
/>
</FFormItem>
<FFormItem label="esc关闭:">
<FRadioGroup
v-model="escClosable"
:options="[
{ label: '是(默认)', value: true },
{ label: '否', value: false },
]"
/>
</FFormItem>
</FForm>
</FSpace>
<FSpace>
<FButton @click="show = true">打开抽屉</FButton>
<FDrawer
v-model:show="show"
title="抽屉"
:maskClosable="maskClosable"
:escClosable="escClosable"
@ok="show = false"
>
<div>我是内容...</div>
<div>我是内容...</div>
<div>我是内容...</div>
</FDrawer>
</FSpace>
</template>

<script setup>
import { ref } from 'vue';
const show = ref(false);
const maskClosable = ref(true);
const escClosable = ref(true);
</script>
64 changes: 36 additions & 28 deletions docs/.vitepress/components/drawer/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,44 +66,52 @@ asyncSubmit.vue
operable.vue
:::

### 关闭抽屉
通过配置项可以控制抽屉的关闭方式。

:::demo
closable.vue
:::

## Drawer Props

| 属性 | 说明 | 类型 | 默认值 |
|------------------|---------------------------------------------------------------------------|-----------------------------------------|-----------------------|
| show | v-model:show,是否显示抽屉 | boolean | `false` |
| displayDirective | 选择渲染使用的指令,if 对应 v-if,show 对应 v-show,使用 show 的时候不会被重置 | string | `show` |
| closable | 是否显示右上角关闭图标 | boolean | `true` |
| mask | 是否显示蒙层 | boolean | `true` |
| maskClosable | 点击蒙层是否允许关闭 | boolean | `true` |
| operable | 仅 mask 为 false 时生效,不显示蒙层时,页面是否可交互 | boolean | `false` |
| title | 标题 | string | - |
| footer | 是否显示底部内容 | boolean | `false` |
| footerBorder | 是否显示底部分割线 | boolean | `false` |
| okText | 确认按钮文字 | string | 确定 |
| okLoading | 确认按钮 Loading 状态 | boolean | `false` |
| showCancel | 是否展示取消按钮 | boolean | `true` |
| cancelText | 取消按钮文字 | string | 取消 |
| dimension | 抽屉尺寸 | string/number | 520 |
| width | 宽度<br/>(即将废弃,推荐使用 dimension) | string/number | 520 |
| 属性 | 说明 | 类型 | 默认值 |
| ---------------- | ------------------------------------------------------------------------------- | --------------------------------------- | --------------------- |
| show | v-model:show,是否显示抽屉 | boolean | `false` |
| displayDirective | 选择渲染使用的指令,if 对应 v-if,show 对应 v-show,使用 show 的时候不会被重置 | string | `show` |
| closable | 是否显示右上角关闭图标 | boolean | `true` |
| mask | 是否显示蒙层 | boolean | `true` |
| maskClosable | 点击蒙层是否允许关闭 | boolean | `true` |
| escClosable | 按下ESC是否允许关闭 | boolean | `true` |
| operable | 仅 mask 为 false 时生效,不显示蒙层时,页面是否可交互 | boolean | `false` |
| title | 标题 | string | - |
| footer | 是否显示底部内容 | boolean | `false` |
| footerBorder | 是否显示底部分割线 | boolean | `false` |
| okText | 确认按钮文字 | string | 确定 |
| okLoading | 确认按钮 Loading 状态 | boolean | `false` |
| showCancel | 是否展示取消按钮 | boolean | `true` |
| cancelText | 取消按钮文字 | string | 取消 |
| dimension | 抽屉尺寸 | string/number | 520 |
| width | 宽度<br/>(即将废弃,推荐使用 dimension) | string/number | 520 |
| hight | 高度,在 placement 为 top 或 bottom 时使用<br/>(即将废弃,推荐使用 dimension) | string/number | 520 |
| placement | 抽屉方向 | `'right'` `'bottom'` `'left'` `'right'` | `'right'` |
| contentClass | 可用于设置内容的类名 | string | - |
| getContainer | 指定 `Drawer` 挂载的 HTML 节点 | () => HTMLElement | `() => document.body` |
| resizable | 是否支持宽度/高度可拖拽 | boolean | `false` |
| resizeMax | 可拖拽的最大尺寸(如:`100``'200px'``'30%'` | number/string | - |
| resizeMin | 可拖拽的最小尺寸(同上) | number/string | - |
| placement | 抽屉方向 | `'right'` `'bottom'` `'left'` `'right'` | `'right'` |
| contentClass | 可用于设置内容的类名 | string | - |
| getContainer | 指定 `Drawer` 挂载的 HTML 节点 | () => HTMLElement | `() => document.body` |
| resizable | 是否支持宽度/高度可拖拽 | boolean | `false` |
| resizeMax | 可拖拽的最大尺寸(如:`100``'200px'``'30%'`| number/string | - |
| resizeMin | 可拖拽的最小尺寸(同上) | number/string | - |

## Drawer Event

| 事件名称 | 说明 | 回调参数 |
|----------|------------------------------------|----------|
| -------- | ------------------------------------ | -------- |
| cancel | 点击遮罩层或右上角叉或取消按钮的回调 | event |
| ok | 点击确定回调 | event |

## Drawer Slots

| 名称 | 说明 |
|---------|-------------------------|
| default | 模态框的内容 |
| title | 模态框的标题 |
| 名称 | 说明 |
| ------- | -------------------------- |
| default | 模态框的内容 |
| title | 模态框的标题 |
| footer | 底部内容,一般是自定义按钮 |
48 changes: 48 additions & 0 deletions docs/.vitepress/components/modal/closable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<FSpace>
<FForm :labelWidth="100">
<FFormItem label="点击蒙层关闭:">
<FRadioGroup
v-model="maskClosable"
:options="[
{ label: '是(默认)', value: true },
{ label: '否', value: false },
]"
/>
</FFormItem>
<FFormItem label="esc关闭:">
<FRadioGroup
v-model="escClosable"
:options="[
{ label: '是(默认)', value: true },
{ label: '否', value: false },
]"
/>
</FFormItem>
</FForm>
</FSpace>
<FSpace>
<FButton @click="show = true">打开弹窗</FButton>
<FModal
v-model:show="show"
title="弹窗"
:maskClosable="maskClosable"
:escClosable="escClosable"
@ok="show = false"
>
<div>我是内容...</div>
<div>我是内容...</div>
<div>我是内容...</div>
</FModal>
</FSpace>
</template>

<script setup>
import { ref } from 'vue';
const show = ref(false);
const maskClosable = ref(true);
const escClosable = ref(true);
</script>
8 changes: 8 additions & 0 deletions docs/.vitepress/components/modal/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ showCancel.vue
maxHeight.vue
:::

### 关闭弹窗
通过配置项可以控制弹窗的关闭方式。

:::demo
closable.vue
:::

## Modal Props

| 属性 | 说明 | 类型 | 默认值 |
Expand All @@ -81,6 +88,7 @@ maxHeight.vue
| closable | 是否显示右上角关闭图标 | Boolean | `true` |
| mask | 是否显示蒙层 | Boolean | `true` |
| maskClosable | 点击蒙层是否允许关闭 | Boolean | `true` |
| escClosable | 按下ESC是否允许关闭 | boolean | `true` |
| type | 类型,可选值为`info` `success` `error` `warning` `warn` `confirm` | string | `-` |
| title | 标题 | String | `-` |
| footer | 是否显示底部内容 | Boolean | `true` |
Expand Down

0 comments on commit 72ca443

Please sign in to comment.