diff --git a/packages/devui-vue/devui/modal/index.ts b/packages/devui-vue/devui/modal/index.ts index 8fed115609..54d40b84cc 100644 --- a/packages/devui-vue/devui/modal/index.ts +++ b/packages/devui-vue/devui/modal/index.ts @@ -1,21 +1,22 @@ -import type { App } from 'vue' -import Modal from './src/modal' -import { ModalService } from './src/services/modal-service' -import { DialogService } from './src/services/dialog-service' -import { inBrowser } from '../shared/util/common-var' +import type { App } from 'vue'; +import Modal from './src/modal'; +import Header from './src/header'; +import Body from './src/body'; +import Footer from './src/footer'; +import { ModalService } from './src/services/modal-service'; +import { inBrowser } from '../shared/util/common-var'; -Modal.install = function(app: App): void { - app.component(Modal.name, Modal) -} - -export { Modal } +export { Modal }; export default { title: 'Modal 弹窗', category: '反馈', status: '100%', install(app: App): void { - app.use(Modal as any) + app.component(Modal.name, Modal); + app.component(Header.name, Header); + app.component(Body.name, Body); + app.component(Footer.name, Footer); if (!inBrowser) { return; @@ -25,10 +26,9 @@ export default { if (!anchorsContainer) { anchorsContainer = document.createElement('div'); anchorsContainer.setAttribute('id', 'd-modal-anchors-container'); - document.body.appendChild(anchorsContainer); + document.body.appendChild(anchorsContainer); } // 新增 modalService app.provide(ModalService.token, new ModalService(anchorsContainer)); - app.provide(DialogService.token, new DialogService(anchorsContainer)); - } -} + }, +}; diff --git a/packages/devui-vue/devui/modal/src/body.tsx b/packages/devui-vue/devui/modal/src/body.tsx new file mode 100644 index 0000000000..0f2c9636a5 --- /dev/null +++ b/packages/devui-vue/devui/modal/src/body.tsx @@ -0,0 +1,8 @@ +import { defineComponent } from 'vue'; + +export default defineComponent({ + name: 'DModalBody', + setup(props, { slots }) { + return () =>
{slots.default?.()}
; + }, +}); diff --git a/packages/devui-vue/devui/modal/src/dialog-types.ts b/packages/devui-vue/devui/modal/src/dialog-types.ts deleted file mode 100644 index dadbc7bb67..0000000000 --- a/packages/devui-vue/devui/modal/src/dialog-types.ts +++ /dev/null @@ -1,95 +0,0 @@ -import type { PropType, ExtractPropTypes } from 'vue' -import { IButtonVariant } from '../../button' - -export interface ButtonOptions { - variant: IButtonVariant - text: string - disabled: boolean - handler: ($event: Event) => void -} - -export const dialogProps = { - // id: { - // type: String, - // required: true - // }, - width: { - type: String, - default: '300px' - }, - maxHeight: { - type: String, - }, - - zIndex: { - type: Number, - default: 1050 - }, - backdropZIndex: { - type: Number, - default: 1049 - }, - - placement: { - type: String as PropType<'center' | 'top' | 'bottom'>, - default: 'center' - }, - offsetX: { - type: String, - default: '0px' - }, - - offsetY: { - type: String, - default: '0px' - }, - - title: { - type: String - }, - - showAnimation: { - type: Boolean, - default: true - }, - backdropCloseable: { - type: Boolean, - default: true - }, - bodyScrollable: { - type: Boolean, - default: true - }, - - escapeable: { - type: Boolean, - default: true - }, - - onClose: { - type: Function as PropType<() => void>, - }, - beforeHidden: { - type: [Promise, Function] as PropType | (() => boolean | Promise)> - }, - - buttons: { - type: Array as PropType, - default: [] - }, - - dialogType: { - type: String as PropType<'standard' | 'success' | 'failed' | 'warning' | 'info'>, - default: 'standard' - }, - - - modelValue: { - type: Boolean, - }, - 'onUpdate:modelValue': { - type: Function as PropType<(value: boolean) => void> - } -} as const - -export type DialogProps = ExtractPropTypes diff --git a/packages/devui-vue/devui/modal/src/dialog.tsx b/packages/devui-vue/devui/modal/src/dialog.tsx deleted file mode 100644 index 787e3d8b36..0000000000 --- a/packages/devui-vue/devui/modal/src/dialog.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { defineComponent, computed, CSSProperties, watch, ref } from 'vue'; -import { DialogProps, dialogProps } from './dialog-types'; -import { useMoveable } from './use-moveable'; - -import { Button } from '../../button'; -import Modal from './modal'; - -import './modal.scss'; -import { Icon } from '../../icon'; - -export default defineComponent({ - name: 'DModal', - inheritAttrs: false, - props: dialogProps, - emits: ['onUpdate:modelValue'], - setup(props: DialogProps, ctx) { - - // 获取鼠标拖拽的偏移量 - const { - movingX, - movingY, - handleRef, - moveElRef, - reset - } = useMoveable(); - - watch(() => props.modelValue, (value) => { - if (value) { - reset(); - } - }); - - // 拖拽的样式 - const movingStyle = computed(() => ({ - position: 'relative', - left: `${movingX.value}px`, - top: `${movingY.value}px`, - })); - - // 容器的样式 - const containerStyle = computed(() => ({ - width: props.width, - maxHeight: props.maxHeight, - transform: `translate(${props.offsetX}, ${props.offsetY})`, - zIndex: props.zIndex - })); - - const iconName = computed(() => { - switch (props.dialogType) { - case 'standard': - return ''; - case 'info': - return 'icon-info-o'; - case 'success': - return 'icon-right-o'; - case 'warning': - return 'icon-warning-o'; - case 'failed': - return 'icon-error-o'; - default: - return ''; - } - }); - - // 处理按钮 - const buttonsRef = computed(() => { - return props.buttons.map((buttonProps, index) => { - const { variant, disabled, handler, text } = buttonProps; - return ( - - ); - }); - }); - - const modalRef = ref<{ onVisibleChange(v: boolean): void; } | null>(); - const closeModal = () => { - modalRef.value?.onVisibleChange?.(false) - } - ctx.expose({ closeModal }); - - return () => ( - -
-
- {!!iconName.value ? ( - - ) : null} - - {props.title} - -
-
- {ctx.slots.default?.()} -
- -
-
- ); - } -}); \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/src/footer.tsx b/packages/devui-vue/devui/modal/src/footer.tsx new file mode 100644 index 0000000000..e6894379fa --- /dev/null +++ b/packages/devui-vue/devui/modal/src/footer.tsx @@ -0,0 +1,8 @@ +import { defineComponent } from 'vue'; + +export default defineComponent({ + name: 'DModalFooter', + setup(props, { slots }) { + return () => ; + }, +}); diff --git a/packages/devui-vue/devui/modal/src/header.tsx b/packages/devui-vue/devui/modal/src/header.tsx new file mode 100644 index 0000000000..0cd7be0a3e --- /dev/null +++ b/packages/devui-vue/devui/modal/src/header.tsx @@ -0,0 +1,8 @@ +import { defineComponent } from 'vue'; + +export default defineComponent({ + name: 'DModalHeader', + setup(props, { slots }) { + return () =>
{slots.default?.()}
; + }, +}); diff --git a/packages/devui-vue/devui/modal/src/modal-types.ts b/packages/devui-vue/devui/modal/src/modal-types.ts index cb3a269af9..4b5bc8e4aa 100644 --- a/packages/devui-vue/devui/modal/src/modal-types.ts +++ b/packages/devui-vue/devui/modal/src/modal-types.ts @@ -1,72 +1,31 @@ -import type { PropType, ExtractPropTypes } from 'vue' +import type { PropType, ExtractPropTypes } from 'vue'; export const modalProps = { - // id: { - // type: String, - // required: true - // }, - width: { - type: String, - default: '300px' - }, - maxHeight: { - type: String, - }, - - zIndex: { - type: Number, - default: 1050 - }, - backdropZIndex: { - type: Number, - default: 1049 - }, - - placement: { - type: String as PropType<'center' | 'top' | 'bottom'>, - default: 'center' - }, - offsetX: { - type: String, - default: '0px' + modelValue: { + type: Boolean, + default: false, }, - - offsetY: { + title: { type: String, - default: '0px' + default: '', }, - - showAnimation: { + lockScroll: { type: Boolean, - default: true + default: true, }, - backdropCloseable: { + closeOnClickOverlay: { type: Boolean, - default: true + default: true, }, - bodyScrollable: { - type: Boolean, - default: true + beforeClose: { + type: Function as PropType<(done: () => void) => void>, }, +}; - escapeable: { - type: Boolean, - default: true - }, +export type EmitName = 'update:modelValue'; - onClose: { - type: Function as PropType<() => void>, - }, - beforeHidden: { - type: [Object, Function] as PropType | (() => boolean | Promise)> - }, +export type EmitEventFn = (event: EmitName, result?: boolean) => void; - modelValue: { - type: Boolean, - }, - 'onUpdate:modelValue': { - type: Function as PropType<(value: boolean) => void> - } -} as const +export type UseModalFn = { handleVisibleChange: (val: boolean) => void }; -export type ModalProps = ExtractPropTypes +export type ModalProps = ExtractPropTypes; diff --git a/packages/devui-vue/devui/modal/src/modal.scss b/packages/devui-vue/devui/modal/src/modal.scss index dda282b5b6..d401ba10d3 100644 --- a/packages/devui-vue/devui/modal/src/modal.scss +++ b/packages/devui-vue/devui/modal/src/modal.scss @@ -3,42 +3,52 @@ @import '../../style/theme/font'; @import '../../style/theme/animation'; -.devui-modal-wrapper { +.devui-modal-mask { justify-content: center; align-items: center; background-color: $devui-shadow; } -.devui-modal-content { - background: $devui-fullscreen-overlay-bg; - border-radius: $devui-border-radius; -} - -.devui-modal-body { - padding: 20px 32px; - color: $devui-text-weak; -} - -.devui-modal-header { - padding: 32px 32px 0; - height: 56px; +.devui-modal { position: relative; - border: none; - user-select: none; + width: 300px; + background-color: $devui-global-bg-normal; .btn-close { position: absolute; right: 20px; top: 20px; - font-size: $devui-font-size-icon; - font-weight: 700; - line-height: 1; + width: 20px; + height: 20px; + line-height: 20px; + text-align: center; color: #000000; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; + + &:hover { + color: $devui-icon-fill-active-hover; + background-color: $devui-list-item-hover-bg; + } } +} + +.devui-modal-content { + background: $devui-fullscreen-overlay-bg; + border-radius: $devui-border-radius; +} + +.devui-modal-header { + width: 100%; + height: 56px; + padding: 32px 32px 0; + font-size: $devui-font-size-card-title; + font-weight: bold; + box-sizing: border-box; + border: none; + user-select: none; .header-alert-icon { display: inline-block; @@ -49,10 +59,23 @@ } } +.devui-modal-body { + padding: 20px 32px; + font-size: $devui-font-size; + color: $devui-text-weak; + box-sizing: border-box; +} + .devui-modal-footer { + width: 100%; border-top: none; text-align: center; padding: 0 32px 24px; + box-sizing: border-box; + + & > * { + margin: 0 4px; + } } .devui-modal-wipe { diff --git a/packages/devui-vue/devui/modal/src/modal.tsx b/packages/devui-vue/devui/modal/src/modal.tsx index 3545007fe4..058f077c4d 100644 --- a/packages/devui-vue/devui/modal/src/modal.tsx +++ b/packages/devui-vue/devui/modal/src/modal.tsx @@ -1,62 +1,38 @@ -import { - computed, - defineComponent, - Transition, -} from 'vue' -import { modalProps, ModalProps } from './modal-types' -import { FixedOverlay } from '../../overlay' +import { defineComponent, toRefs, Transition } from 'vue'; +import { modalProps, ModalProps } from './modal-types'; +import { Icon } from '../../icon'; +import { FixedOverlay } from '../../overlay'; +import { useModal } from './use-modal'; +import DModalHeader from './header'; +import DModalBody from './body'; import './modal.scss'; export default defineComponent({ name: 'DModal', + inheritAttrs: false, props: modalProps, - emits: ['onUpdate:modelValue'], - setup(props: ModalProps, ctx) { - const animatedVisible = computed(() => { - return props.showAnimation ? props.modelValue : true; - }); - - // 处理取消事件 - const onVisibleChange = (value: boolean) => { - const update = props['onUpdate:modelValue']; - if (value) { - update?.(value); - } else { - const beforeHidden = props.beforeHidden; - const close = (enabledClose: boolean) => { - if (enabledClose) { - update?.(false); - props.onClose?.(); - } - } - // true: 确认关闭 - // false: 仍然开启 - const result = (typeof beforeHidden === 'function' ? beforeHidden() : beforeHidden) ?? true; - if (result instanceof Promise) { - result.then(close); - } else { - close(result); - } - } - } - - ctx.expose({ onVisibleChange }); + emits: ['update:modelValue'], + setup(props: ModalProps, { slots, attrs, emit, expose }) { + const { modelValue, lockScroll, closeOnClickOverlay, title } = toRefs(props); + const { handleVisibleChange } = useModal(props, emit); + expose({ handleVisibleChange }); return () => ( - - {animatedVisible.value ? ctx.slots.default?.() : null} + visible={modelValue.value} + onUpdate:visible={handleVisibleChange} + background-class='devui-modal-mask' + background-block={lockScroll.value} + backdrop-close={closeOnClickOverlay.value}> + +
+ handleVisibleChange(false)}> + {slots.header ? slots.header() : title.value && {title.value}} + {slots.default?.()} + {slots.footer?.()} +
- ) - } -}) - + ); + }, +}); diff --git a/packages/devui-vue/devui/modal/src/services/dialog-service.ts b/packages/devui-vue/devui/modal/src/services/dialog-service.ts deleted file mode 100644 index 31eb9dd811..0000000000 --- a/packages/devui-vue/devui/modal/src/services/dialog-service.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Slot, InjectionKey } from 'vue'; -// import {h, ref, SetupContext, defineComponent, customRef} from 'vue' -import { CommonModalService, ModalOpenResult } from './common-modal-service'; -import Dialog from '../dialog'; -import { ButtonOptions, DialogProps } from '../dialog-types'; - - -export interface DialogOptions { - width: string - maxHeight: string - zIndex: number - backdropZIndex: number - placement: 'center' | 'top' | 'bottom' - offsetX: string - offsetY: string - showAnimation: boolean - backdropCloseable: boolean - escapeable: boolean - bodyScrollable: boolean - dialogtype: 'standard' | 'success' | 'failed' | 'warning'| 'info' - - title: string - content: Slot - buttons: ButtonOptions[] - - onClose(): void - beforeHidden: (() => boolean | Promise) | Promise -} - -export class DialogService extends CommonModalService { - - static token = 'DIALOG_SERVICE_TOKEN' as unknown as InjectionKey; - - component(): any { - return Dialog; - } - - open(props: Partial = {}): ModalOpenResult & {updateButtonOptions(options: ButtonOptions[]): void;} { - // TODO:手动的方式可能抛弃了 content 内部的响应式,这里需要再优化。 - const anchor = document.createElement('div'); - this.anchorContainer.appendChild(anchor); - - const {content, ...resProps} = props; - - const needHideOrNot = (value: boolean) => { - if (!value) { - hide(); - } - } - - const renderOrigin = (props: typeof resProps, onUpdateModelValue = needHideOrNot) => { - return this.renderModal(anchor, { - ...props, - modelValue: true, - 'onUpdate:modelValue': onUpdateModelValue - }, {default: content}); - } - - - - // 隐藏按钮 - const hide = () => { - const vnode = renderOrigin(resProps, (value: boolean) => { - if (!value) { - this.renderModal(anchor, {...resProps, modelValue: false}); - this.renderNull(anchor); - } else { - renderOrigin(resProps); - } - }); - vnode.component.exposed.closeModal?.(); - } - - // 更新按钮选项 - const updateButtonOptions = (buttonOptions: ButtonOptions[]) => { - const { buttons, ...innerResProps } = resProps; - const newButtonOptions = buttons.map((option, index) => ({ - ...option, - ...buttonOptions[index] - })); - renderOrigin({...innerResProps, buttons: newButtonOptions}); - } - - // 先渲染一次,触发动画用 - this.renderModal(anchor, { modelValue: false }); - - // 再渲染详细内容 - renderOrigin(resProps); - - return { hide, updateButtonOptions } - - // TODO: 这个需要再考虑设计 - // const CurrentDialog = defineComponent((currentProps: typeof props, ctx: SetupContext) => { - // const dialogRef = ref<{closeModal(): void;} | null>(); - // const visibleRef = ref(true); - // const buttonsRef = ref(currentProps.buttons); - // ctx.expose({ - // closeModal() { - // dialogRef.value?.closeModal?.(); - // }, - // updateButtons(buttons: ButtonOptions) { - // buttonsRef.value = buttonsRef.value.map((option, index) => ({ - // ...option, - // ...buttons[index] - // })); - // } - // }); - // return () => { - // const {content, ...resProps} = currentProps; - // return h(Dialog, { - // ...resProps, - // ref: dialogRef, - // modelValue: visibleRef.value, - // 'onUpdate:modelValue': (value) => visibleRef.value = value - // }, {default: content}); - // }; - // }); - } -} \ No newline at end of file diff --git a/packages/devui-vue/devui/modal/src/services/modal-service.ts b/packages/devui-vue/devui/modal/src/services/modal-service.ts index 6e7ffe2ff2..b7d2e57f78 100644 --- a/packages/devui-vue/devui/modal/src/services/modal-service.ts +++ b/packages/devui-vue/devui/modal/src/services/modal-service.ts @@ -1,33 +1,25 @@ -import { InjectionKey, Slot } from 'vue'; +import type { InjectionKey, Slot } from 'vue'; import { ModalProps } from '../modal-types'; import { CommonModalService, ModalOpenResult } from './common-modal-service'; -import Modal from '../modal'; +import DModal from '../modal'; -export interface ModalOptions { - width: string - maxHeight: string - zIndex: number - backdropZIndex: number - placement: 'center' | 'top' | 'bottom' - offsetX: string - offsetY: string - showAnimation: boolean - backdropCloseable: boolean - escapeable: boolean - bodyScrollable: boolean - content: Slot +let vm; - onClose(): void - beforeHidden: (() => boolean | Promise) | Promise +export interface ModalOptions { + title?: string; + lockScroll?: boolean; + closeOnClickOverlay?: boolean; + header: Slot; + content: Slot; + footer: Slot; + beforeClose: (done: () => void) => void; } - export class ModalService extends CommonModalService { - static token = 'MODAL_SERVICE_TOKEN' as unknown as InjectionKey; - component(): any { - return Modal; + component(): unknown { + return DModal; } open(props: Partial = {}): ModalOpenResult { @@ -35,25 +27,28 @@ export class ModalService extends CommonModalService { const anchor = document.createElement('div'); this.anchorContainer.appendChild(anchor); - const { content, ...resProps } = props; + const { header, content, footer, ...resProps } = props; const needHideOrNot = (value: boolean) => { if (!value) { hide(); } - } + }; const renderOrigin = (props: typeof resProps, onUpdateModelValue = needHideOrNot) => { - return this.renderModal(anchor, { - ...props, - modelValue: true, - 'onUpdate:modelValue': onUpdateModelValue - }, { default: content }); - } - + return this.renderModal( + anchor, + { + ...props, + modelValue: true, + 'onUpdate:modelValue': onUpdateModelValue, + }, + { header, default: content, footer } + ); + }; // 隐藏按钮 const hide = () => { - const vnode = renderOrigin(resProps, (value: boolean) => { + renderOrigin(resProps, (value: boolean) => { if (!value) { this.renderModal(anchor, { ...resProps, modelValue: false }); this.renderNull(anchor); @@ -61,16 +56,15 @@ export class ModalService extends CommonModalService { renderOrigin(resProps); } }); - vnode.component.exposed.onVisibleChange?.(false); - } - + vm.component.exposed.handleVisibleChange?.(false); + }; // 先渲染一次,触发动画用 this.renderModal(anchor, { modelValue: false }); // 再渲染详细内容 - renderOrigin(resProps); + vm = renderOrigin(resProps); - return { hide } + return { hide }; } } diff --git a/packages/devui-vue/devui/modal/src/use-modal.ts b/packages/devui-vue/devui/modal/src/use-modal.ts new file mode 100644 index 0000000000..0b7f0a7be5 --- /dev/null +++ b/packages/devui-vue/devui/modal/src/use-modal.ts @@ -0,0 +1,14 @@ +import { ModalProps, EmitEventFn, UseModalFn } from './modal-types'; + +export function useModal(props: ModalProps, emit: EmitEventFn): UseModalFn { + function close(): void { + emit('update:modelValue', false); + } + function handleVisibleChange(val: boolean): void { + if (!val) { + props.beforeClose ? props.beforeClose(close) : close(); + } + } + + return { handleVisibleChange }; +} diff --git a/packages/devui-vue/docs/components/modal/index.md b/packages/devui-vue/docs/components/modal/index.md index 5d7530edc4..2873819cb6 100644 --- a/packages/devui-vue/docs/components/modal/index.md +++ b/packages/devui-vue/docs/components/modal/index.md @@ -1,395 +1,194 @@ # Modal 模态弹窗 -模态对话框。 -### 何时使用 -1.需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。 -2.弹窗起到与用户进行交互的作用,用户可以在对话框中输入信息、阅读提示、设置选项等操作。 +模态框。 -#### 标准对话框 -使用dialogService可拖拽的标准对话框。 -:::demo -```vue - - -``` -::: +#### 何时使用 -#### 自定义对话框 -使用modalService可以自定义对话框内的所有内容。 -:::demo +1.需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。 -```vue - - +2.Modal 起到与用户进行交互的作用,用户可以在 Modal 中输入信息、阅读提示、设置选项等操作。 -``` -::: +### 基础用法 -#### 拦截对话框关闭 -通过 beforeHidden 设置在关闭弹出框时的拦截方法。 -:::demo +:::demo `v-model`双向绑定,控制 Modal 是否显示;`title`参数设置 Modal 标题。 ```vue + - ``` -::: +::: -#### 信息提示 -各种类型的信息提示框。 -:::demo -```vue - - - -``` -::: +:::demo `header`插槽可以自定义 Modal 顶部区域,子组件`d-modal-header`为顶部区域提供了默认样式,自定义样式可通过在子组件设置`style/class`实现。`footer`插槽同理。 -#### 更新标准弹出框按钮状态 -通过update方法来更新dialog配置的buttons配置。 -:::demo ```vue ``` + ::: -#### 配置按钮自动获得焦点 -配置dialogService的buttons中的autofocus属性可以设置按钮自动获得焦点,可以通过回车直接触发按钮点击。 -:::demo +### 关闭前回调 + +:::demo `before-close`在用户点击关闭按钮或者遮罩层时会被调用,可在完成某些异步操作后,通过`done`参数关闭。 + ```vue + ``` + ::: -#### 通过外层fixed同时避免滚动和抖动 -通过外层fixed同时避免滚动和抖动,在使用这种方式时,页面内所有fixed元素需要给定具体的位置值,使用默认定位值会导致位置偏移。 -:::demo +### 服务方式调用 + +:::demo 通过`inject('MODAL_SERVICE_TOKEN')`获取`ModalService`实例,调用实例上的`open`方法打开 Modal。 + ```vue ``` + ::: +### d-modal 参数 -### API -Modal 和 Dialog 均以 service 方式来构造。 +| 属性 | 类型 | 默认 | 说明 | +| ---------------------- | ---------------- | ----- | ------------------------------------------ | +| v-model | `boolean` | false | 是否显示 Modal | +| title | `string` | - | 可选,Modal 的标题 | +| lock-scroll | `boolean` | true | 可选,是否将 body 滚动锁定 | +| close-on-click-overlay | `boolean` | true | 可选,点击遮罩层是否能关闭 Modal | +| before-close | `(done) => void` | - | 可选,关闭前的回调,调用 done 可关闭 Modal | -他们通过这种方式引入: -```vue - -{ - setup() { - const modalService = inject('MODAL_SERVICE_TOKEN'); - const dialogService = inject('DIALOG_SERVICE_TOKEN'); - } -} -``` -#### Modal - -ModalService.open(props: ModalOptions) - -ModalOptions 属性 - -| 属性 | 类型 | 默认 | 说明 | -| :---------------: | :-------------------------------------------------------: | :------: | :----------------------------------------------- | -| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | -| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | -| backdropZIndex | `number` | 1049 | 可选,如果为 true,背景不能滚动 | -| placement | `'center' \| 'top' \| 'bottom'` | 'center' | 可选,弹出框出现的位置 | -| offsetX | `string` | '0px' | 可选,弹出框纵向偏移 | -| offsetY | `string` | '0px' | 可选,弹出框横向偏移 | -| bodyScrollable | `boolean` | true | 可选,modal 打开后,body是否可滚动,默认可滚动。 | -| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框 | -| showAnimation | `boolean` | true | 可选,是否显示动画 | -| escapable | `boolean` | true | 可选,点击背景触发的事件 | -| content | `Slot` | true | 可选,弹出框内容 | -| onClose | `() => void` | -- | 可选,弹出框关闭之后回调的函数 | -| beforeHidden | `(() => Promise \| boolean) \| Promise` | -- | 可选,关闭窗口之前的回调 | - -#### Dialog - -DialogService.open(props: DialogOptions) - -DialogOptions 属性 - -| 属性 | 类型 | 默认 | 说明 | -| :---------------: | :-------------------------------------------------------: | :--------: | :----------------------------------------------------- | -| width | `string` | -- | 可选,弹出框宽度(e.g '300px') | -| zIndex | `number` | 1050 | 可选,弹出框 z-index 值 | -| backdropZIndex | `number` | 1049 | 可选,如果为 true,背景不能滚动 | -| placement | `'center' \| 'top' \| 'bottom'` | 'center' | 可选,弹出框出现的位置 | -| offsetX | `string` | '0px' | 可选,弹出框纵向偏移 | -| offsetY | `string` | '0px' | 可选,弹出框横向偏移 | -| bodyScrollable | `boolean` | true | 可选,modal 打开后,body是否可滚动,默认可滚动。 | -| backdropCloseable | `boolean` | true | 可选,点击空白处是否能关闭弹出框 | -| showAnimation | `boolean` | true | 可选,是否显示动画 | -| escapable | `boolean` | true | 可选,点击背景触发的事件 | -| draggable | `boolean` | true | 可选,弹出框是否可拖拽 | -| dialogType | `'standard'\|'success'\|'failed'\|'warning'\|'info'` | 'standard' | 可选,弹出框类型,有四种选择 | -| title | `string` | -- | 可选,弹出框 title | -| content | `Slot` | -- | 可选,弹出框内容,支持字符串和组件 | -| buttons | `ButtonOptions[]` | [] | 可选,弹出框按钮,支持自定义文本、样式、禁用、点击事件 | -| onClose | `() => void` | -- | 可选,弹出框关闭之后回调的函数 | -| beforeHidden | `(() => Promise \| boolean) \| Promise` | -- | 可选,关闭窗口之前的回调 | - -### Other - -ButtonOptions 定义 -| 属性 | 类型 | 默认 | 说明 | -| :-------: | :-----------------------: | :---: | :----------------- | -| text | `string` | -- | 可选,按钮文本内容 | -| handler | `($event: Event) => void` | -- | 可选,按钮点击事件 | -| autofocus | `boolean` | false | 可选,自动聚焦 | -| disabled | `boolean` | false | 可选,禁用按钮 | +### d-modal 插槽 +| 名称 | 说明 | +| ------- | ----------------- | +| default | Modal 内容 | +| header | 自定义 Modal 顶部 | +| footer | 自定义 Modal 底部 |