代码演示
如何引入
<script setup lang="ts">
import { Modal } from '@fibrous/semi-ui-vue';
</script>
基本
对话框用 v-model:visible 控制显示。v-model:visible 只在取消路径更新:取消按钮、关闭按钮、遮罩和 Esc;onCancel 返回 Promise 时,在 fulfill 后更新,reject 则保持打开。点击确定只触发 @ok,由使用方把 visible 设为 false。@cancel 回调执行时,父级的 visible 仍为 true。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const handleOk = () => {
visible.value = false;
console.log('Ok button clicked');
};
const handleCancel = () => {
console.log('Cancel button clicked');
};
const handleAfterClose = () => {
console.log('After Close callback executed');
};
</script>
<template>
<Button @click="visible = true">打开弹窗</Button>
<Modal v-model:visible="visible" closeOnEsc title="基本对话框" @afterClose="handleAfterClose" @cancel="handleCancel" @ok="handleOk">
This is the content of a basic modal.
<br />
More content...
</Modal>
</template>底部撑满
设置 footerFill 为 true 可使 Modal footer 底部按钮撑满排列
点击遮罩层不可关闭
修改 maskClosable 为 false 则不可通过点击遮罩层来关闭对话框。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const close = () => {
visible.value = false;
};
</script>
<template>
<Button @click="visible = true">点击遮罩层不可关闭</Button>
<Modal v-model:visible="visible" :maskClosable="false" title="对话框标题" @ok="close">
<p>This is a modal that cannot be closed by clicking on the mask.</p>
<p>More content...</p>
</Modal>
</template>自定义按钮文字
通过设置 okText 与 cancelText 属性可自定义按钮显示的文字。
注意:命令式调用的 Modal 渲染在组件树之外,读不到 ConfigProvider、LocaleProvider 提供的语言包,需要通过这两个属性来设置文本,或者使用 Modal.useModal。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const close = () => {
visible.value = false;
};
</script>
<template>
<Button @click="visible = true">自定义按钮文字</Button>
<Modal v-model:visible="visible" cancelText="No, thanks." okText="Sounds great!" title="自定义按钮文字" @ok="close">
<p>This is a modal with customized button texts.</p>
<p>More content...</p>
</Modal>
</template>自定义按钮属性
通过设置 okButtonProps 与 cancelButtonProps 属性可自定义按钮的属性。其中的 onClick 先于内置处理调用,不会替换内置处理。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const close = () => {
visible.value = false;
};
</script>
<template>
<Button @click="visible = true">自定义按钮属性</Button>
<Modal v-model:visible="visible" :cancelButtonProps="{ size: 'small', disabled: true }" :okButtonProps="{ size: 'small', type: 'warning' }" title="自定义按钮属性" @ok="close">
<p>This is a modal with customized button props.</p>
<p>More content...</p>
</Modal>
</template>自定义对话框头部和页脚
如果需要实现更丰富的个性化需求,可以通过 #header 插槽自定义头部,#footer 插槽自定义页脚的按钮。传入空的 #header 插槽(<template #header />)时不展示头部区域;不需要显示任何按钮时,同样可以传入空的 #footer 插槽。
自定义对话框的样式
通过设置 style 可以自定义样式及位置如 style.top,也可以通过 centered 使对话框居中显示。也可以通过设置 maskStyle 自定义遮罩样式,及 bodyStyle 自定义对话框内容样式。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const close = () => {
visible.value = false;
};
</script>
<template>
<Button @click="visible = true">自定义对话框样式</Button>
<Modal v-model:visible="visible" :bodyStyle="{ overflow: 'auto', height: '200px' }" centered title="自定义样式" @ok="close">
<p :style="{ lineHeight: 1.8 }">Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统。设计系统包含设计语言以及一整套可复用的前端组件,帮助设计师与开发者更容易地打造高质量的、用户体验一致的、符合设计规范的 Web 应用。</p>
<p :style="{ lineHeight: 1.8 }">区别于其他的设计系统而言,Semi Design 以用户中心、内容优先、设计人性化为设计理念,具有以下优势:</p>
<ul>
<li>
<p>Semi Design 以内容优先进行设计。</p>
</li>
<li>
<p>更容易地自定义主题。</p>
</li>
<li>
<p>适用国际化场景。</p>
</li>
<li>
<p>效率场景加入人性化关怀</p>
</li>
</ul>
</Modal>
</template>自定义的对话框
通过灵活使用 #header、#footer 等插槽可以实现一个完全自定义的对话框。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { IconSemiLogo, IconVigoLogo } from '@fibrous/semi-icons-vue';
import { Button, List, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const data = [
{
icon: IconSemiLogo,
title: 'Boost new feature adoption with Integration',
content: 'Sample data is prepared for you to demonstrate how Integration may be useful for your team',
},
{
icon: IconVigoLogo,
title: 'Introducing Dark Mode',
content: 'Sample data is prepared for you to demonstrate how Integration may be useful for your team',
},
{
icon: IconSemiLogo,
title: 'New List Component',
content: 'Sample data is prepared for you to demonstrate how Integration may be useful for your team',
},
];
const btnStyle = {
width: '240px',
margin: '4px 50px',
};
</script>
<template>
<Button @click="visible = true">自定义对话框</Button>
<Modal v-model:visible="visible">
<template #header />
<h3 :style="{ textAlign: 'center', fontSize: '24px', margin: '40px' }">Semi Design New Features</h3>
<List :dataSource="data" :split="false">
<template #item="{ item }">
<List.Item>
<template #header>
<component :is="item.icon" :style="{ fontSize: '48px' }" />
</template>
<template #main>
<div>
<h6 :style="{ margin: 0, fontSize: '16px' }">{{ item.title }}</h6>
<p :style="{ marginTop: '4px', color: 'var(--semi-color-text-1)' }">{{ item.content }}</p>
</div>
</template>
</List.Item>
</template>
</List>
<template #footer>
<div :style="{ textAlign: 'center' }">
<Button :style="btnStyle" theme="solid" type="primary" @click="visible = false">Continue</Button>
<Button :style="btnStyle" theme="borderless" type="primary" @click="visible = false"> Learn more features </Button>
</div>
</template>
</Modal>
</template>全屏 Modal
使用 fullScreen 可以开启全屏对话框
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
const close = () => {
visible.value = false;
};
</script>
<template>
<Button @click="visible = true">打开全屏弹窗</Button>
<Modal v-model:visible="visible" fullScreen title="全屏对话框标题" @ok="close">
<p>This is a full screen modal</p>
<p>More content...</p>
</Modal>
</template>命令式调用
使用 confirm() 可以设置一个确认框。支持各种类型的信息提示。命令式调用的 title、content、icon、closeIcon、header、footer 接收 ModalNode:字符串、VNode,或返回 VNodeChild 的函数(按函数式组件渲染,可以 inject)。其他 Modal 支持的选项都可以传入。
代码
<script setup lang="ts">
import { h } from 'vue';
import { IconSend } from '@fibrous/semi-icons-vue';
import { Button, Modal } from '@fibrous/semi-ui-vue';
const success = () => Modal.success({ title: 'This is a success message', content: 'bla bla bla...' });
const info = () => Modal.info({ title: 'Here is some info', content: 'bla bla bla...' });
const error = () => Modal.error({ title: 'Unfortunately, there is an error', content: 'bla bla bla...' });
const warning = () => Modal.warning({ title: 'Warning: be cautious ahead', content: 'bla bla bla...' });
const confirm = () => Modal.confirm({ title: 'Are you sure ?', content: 'bla bla bla...' });
const custom = () =>
Modal.info({
title: 'This is a custom modal',
content: 'bla bla bla...',
icon: h(IconSend),
cancelButtonProps: { theme: 'borderless' },
okButtonProps: { theme: 'solid' },
});
</script>
<template>
<div>
<Button @click="info">Info</Button>
<br />
<br />
<Button @click="success">Success</Button>
<br />
<br />
<Button type="danger" @click="error">Error</Button>
<br />
<br />
<Button type="warning" @click="warning">Warning</Button>
<br />
<br />
<Button type="primary" @click="confirm">Confirm</Button>
<br />
<br />
<Button @click="custom">Custom</Button>
</div>
</template>Hooks 用法
Modal.useModal() 返回 [modal, Holder]。把 <Holder /> 放在需要读取上下文的位置,通过 modal.confirm 等方法创建的对话框就能读取该位置的 provide、ConfigProvider 与语言包。
代码
<script setup lang="ts">
import en_GB from '@fibrous/semi-foundation/locale/source/en_GB';
import { Button, ConfigProvider, Modal } from '@fibrous/semi-ui-vue';
const [modal, Holder] = Modal.useModal();
const config = { title: 'This is a success message', content: 'Context consumer' };
</script>
<template>
<ConfigProvider :locale="en_GB">
<div>
<Button @click="modal.confirm(config)">Confirm Modal</Button>
</div>
<Holder />
</ConfigProvider>
</template>可拖拽 Modal
通过 #modal="{ modal }" 插槽自定义渲染 Modal 内容,modal 是 role="dialog" 元素的 VNode,用 <component :is="modal" /> 放置。可拖拽 Modal 通过 DragMove 组件实现。
代码
<script setup lang="ts">
import { ref } from 'vue';
import { Button, DragMove, Modal } from '@fibrous/semi-ui-vue';
const visible = ref(false);
</script>
<template>
<div>
<Button @click="visible = true">Open Modal</Button>
<Modal v-model:visible="visible" centered title="可拖拽Modal">
<template #modal="{ modal }">
<DragMove positionStrategy="relative">
<component :is="modal" />
</DragMove>
</template>
<p>This is the content of a basic sidesheet.</p>
<p>Here is more content...</p>
</Modal>
</div>
</template>API 参考
Modal
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| bodyStyle | 对话框内容区的样式。 | StyleValue | semiGlobalDefault("Modal", "bodyStyle") |
| cancelButtonProps | 取消按钮的属性。autoFocus 为 true 时打开后聚焦该按钮;class、style 落在按钮上;onClick 先于内置的取消处理调用,不会替换内置处理。 | ModalButtonProps | semiGlobalDefault("Modal", "cancelButtonProps") |
| cancelLoading | 取消按钮是否加载中;不传时跟随 onCancel 返回的 Promise,显式传入 false 关闭该行为。 | boolean | semiGlobalDefault("Modal", "cancelLoading") |
| cancelText | 取消按钮文字,缺省取语言包 Modal.cancel。 | string | semiGlobalDefault("Modal", "cancelText") |
| centered | 是否垂直居中显示。 | boolean | semiDefault("Modal", "centered", false) |
| closable | 是否显示右上角的关闭按钮。 | boolean | semiDefault("Modal", "closable", true) |
| closeOnEsc | 是否允许按 Esc 取消对话框。 | boolean | semiDefault("Modal", "closeOnEsc", true) |
| confirmLoading | 确认按钮是否加载中;不传时跟随 onOk 返回的 Promise,显式传入 false 关闭该行为。 | boolean | semiGlobalDefault("Modal", "confirmLoading") |
| footerFill | 默认页脚的两个按钮是否撑满排列。 | boolean | semiGlobalDefault("Modal", "footerFill") |
| fullScreen | 是否全屏显示,开启后 width、height 不再生效。 | boolean | semiDefault("Modal", "fullScreen", false) |
| getPopupContainer | 指定弹层渲染到的父级 DOM。自定义容器需要设置 position: relative;这会改变浮层的 DOM 位置,不改变视图位置。 | Type(() => HTMLElement) | undefined |
| hasCancel | 默认页脚是否显示取消按钮。 | boolean | semiDefault("Modal", "hasCancel", true) |
| height | 对话框高度,数字按像素处理,字符串为合法 CSS 长度。 | string | number | semiGlobalDefault("Modal", "height") |
| keepDOM | 关闭时是否保留对话框内部节点而不销毁。 | boolean | semiDefault("Modal", "keepDOM", false) |
| lazyRender | 配合 keepDOM 使用;为 true 时,首次显示之前不渲染对话框。 | boolean | semiDefault("Modal", "lazyRender", true) |
| mask | 是否显示遮罩。 | boolean | semiDefault("Modal", "mask", true) |
| maskClosable | 是否允许点击遮罩取消对话框。 | boolean | semiDefault("Modal", "maskClosable", true) |
| maskFixed | 遮罩限定在自定义容器内时,是否仍以 fixed 定位覆盖整个视口并按模态处理(aria-modal、页面 inert、Tab 锁定、body 滚动锁定)。 | boolean | semiDefault("Modal", "maskFixed", false) |
| maskStyle | 遮罩的样式。 | StyleValue | semiGlobalDefault("Modal", "maskStyle") |
| modalContentClass | 对话框内容元素的类名。 | string | semiGlobalDefault("Modal", "modalContentClass") |
| motion | 是否启用进出场动画。 | boolean | semiDefault("Modal", "motion", true) |
| okButtonProps | 确认按钮的属性。autoFocus 为 true 时打开后聚焦该按钮;class、style 落在按钮上;onClick 先于内置的确认处理调用,不会替换内置处理。 | ModalButtonProps | semiGlobalDefault("Modal", "okButtonProps") |
| okText | 确认按钮文字,缺省取语言包 Modal.confirm。 | string | semiGlobalDefault("Modal", "okText") |
| okType | 确认按钮的类型。 | OKType | semiDefault("Modal", "okType", "primary") |
| preventScroll | 组件内部调用 focus 时是否阻止浏览器滚动到被聚焦元素,不影响使用方自己的 focus 调用。 | boolean | semiGlobalDefault("Modal", "preventScroll") |
| size | 对话框宽度档位:small 为 448px,medium 为 684px,large 为 920px,full-width 为 100vw - 64px。 | Size | semiDefault("Modal", "size", "small") |
| title | 纯文本标题,同时作为对话框的可访问名称;同时传入 #title 插槽时以插槽为准。声明为 prop,不会作为原生 title 属性落到元素上。 | string | semiGlobalDefault("Modal", "title") |
| visible | 对话框是否可见,配合 v-model:visible 使用。 | boolean | semiDefault("Modal", "visible", false) |
| width | 对话框宽度,数字按像素处理,字符串为合法 CSS 长度;不传时由 size 决定。 | string | number | semiGlobalDefault("Modal", "width") |
| zIndex | 弹层外层的 z-index。 | number | semiDefault("Modal", "zIndex", 1000) |
| onCancel | 取消按钮、关闭按钮、遮罩和 Esc 触发;按 Esc 时参数为原生 KeyboardEvent。返回 Promise 时取消按钮保持加载,fulfill 后才更新 v-model:visible,reject 时保持打开;回调执行时父级的 visible 仍为 true。保留为函数 prop 以读取返回值,使用方照常写 @cancel。 | Type((event: MouseEvent | KeyboardEvent) => void | Promise<unknown>) | undefined |
| onOk | 点击确认按钮时调用;返回 Promise 时确认按钮保持加载直到落定。组件不会自行关闭,由使用方把 visible 设为 false。保留为函数 prop 以读取返回值,使用方照常写 @ok。 | Type((event: MouseEvent) => void | Promise<unknown>) | undefined |
Events
| 事件 | 说明 | 回调参数 |
|---|---|---|
| update:visible | 取消路径(取消按钮、关闭按钮、遮罩、Esc)完成后触发,值为 false,供 v-model:visible 回写。确认只触发 onOk,不触发该事件。 | [visible: boolean] |
| afterClose | 对话框完全关闭后触发;显示期间被卸载时也会触发一次。 | [] |
Slots
| 插槽 | 说明 | 作用域参数 |
|---|---|---|
| default | 对话框的正文。 | any |
| title | 标题,优先于 title 属性,同时作为对话框的可访问名称。 | any |
| header | 完全替换默认头部(图标、标题与关闭按钮)。传入空插槽时隐藏头部区域。 | any |
| footer | 完全替换默认页脚按钮。传入空插槽时隐藏页脚区域。 | any |
| icon | 标题前的图标。 | any |
| closeIcon | 关闭按钮中的图标;空插槽时回落到默认图标。 | any |
| modal | 自定义渲染对话框本身,参数 modal 是 role=dialog 元素的 VNode,用 <component :is="modal" /> 放置。 | Type{ modal: VNode<RendererNode, RendererElement, { [key: string]: any; }>; } |
Exposes
| 名称 | 说明 | 类型 |
|---|---|---|
| root | Portal 内的最外层元素,未渲染时为 null。 | HTMLDivElement | null |
role 与全部 aria-* 属性落在 role="dialog" 元素上,style 落在 .semi-modal 对话框盒子上,class 与其他原生属性落在 portal 内最外层元素上。组件版 Modal 没有 content 属性,对话框内容写在默认插槽中;content 选项只用于下面的命令式方法。
Modal.method()
Modal.infoModal.successModal.errorModal.warningModal.confirm
ModalNode 为 string | VNode | (() => VNodeChild),函数按函数式组件渲染,可以 inject。
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| afterClose | 对话框完全关闭后的回调函数 | () => void | - |
| bodyStyle | 对话框内容的样式 | StyleValue | - |
| cancelButtonProps | 取消按钮的属性,其中的 onClick 先于内置处理调用,不会替换内置处理 | ModalButtonProps | - |
| cancelText | 取消按钮的文字 | string | - |
| centered | 是否居中显示 | boolean | false |
| class | 可用于设置样式类名 | string | object | array | - |
| closable | 是否显示右上角的关闭按钮 | boolean | true |
| closeIcon | 关闭按钮的 icon | ModalNode | <IconClose /> |
| confirmLoading | 确认按钮 loading;未设置时跟随 onOk 返回 Promise 的 pending 状态,显式传 false 关闭该行为 | boolean | - |
| content | 对话框内容 | ModalNode | - |
| direction | 文字方向。静态方法在任何 ConfigProvider 之外渲染,需要自行传入;useModal 的方法默认跟随所在位置的 ConfigProvider | 'ltr' | 'rtl' | - |
| footer | 对话框底部,null 时隐藏底部区域 | ModalNode | null | - |
| footerFill | 底部按钮是否撑满 | boolean | false |
| header | 对话框头部,null 时隐藏头部区域 | ModalNode | null | - |
| height | 高度 | string | number | - |
| icon | 自定义 icon | ModalNode | - |
| mask | 是否显示遮罩 | boolean | true |
| maskClosable | 是否允许通过点击遮罩来关闭对话框 | boolean | true |
| maskStyle | 遮罩的样式 | StyleValue | - |
| modalContentClass | 可用于设置对话框内容的样式类名 | string | - |
| modalRender | 自定义渲染 Modal,参数是 role="dialog" 元素的 VNode | (modal: VNode) => VNodeChild | - |
| motion | 动画效果开关,update 中修改同样生效 | boolean | true |
| okButtonProps | 确认按钮的属性,其中的 onClick 先于内置处理调用,不会替换内置处理 | ModalButtonProps | - |
| okText | 确认按钮的文字 | string | - |
| okType | 确认按钮的类型 | OKType | primary |
| style | 可用于设置样式 | StyleValue | - |
| title | 对话框的标题 | ModalNode | - |
| width | 宽度,未设置时由 size 决定(small 为 448) | string | number | - |
| zIndex | 遮罩的 z-index 值 | number | 1000 |
| onCancel | 取消回调,返回 Promise 时 fulfill 后自动关闭,reject 则保持打开;按 Esc 关闭时参数为原生 KeyboardEvent | (event: MouseEvent | KeyboardEvent) => void | Promise<unknown> | - |
| onOk | 点击确定回调,参数是点击事件,返回 Promise 时 fulfill 后自动关闭,reject 则保持打开 | (event: MouseEvent) => void | Promise<unknown> | - |
aria-* 与 data-* 选项落在对话框上。以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。update 接收与以上函数相同的选项(ModalConfirmProps),合并到当前配置,不接收 type。
const modal = Modal.info({ title: '标题' });
modal.update({
title: '更新的标题',
content: '更新的内容',
});
modal.destroy();
Modal.destroyAll
使用 Modal.destroyAll() 可以销毁命令式及以上.info()等创建的弹窗。
Modal.useModal当你需要读取上下文时,可以通过const [modal, Holder] = Modal.useModal()得到 modal 对象与 Holder 组件,把<Holder />放进相应位置。此时通过 modal 创建的对话框将得到 Holder 所在位置的所有上下文(provide、ConfigProvider、语言包)。modal 对象拥有与 Modal.method 相同的创建方法。app.use(Modal)可选。安装后命令式对话框用该 app 的上下文渲染,可以读到app.provide()的值和全局注册的组件;Toast、Notification、Modal 的静态方法共用这一记录,安装其中任何一个即对三者生效,多个 app 都安装时以最后一次为准。
Accessibility
ARIA
WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
- 组件版 Modal 的 role 为
dialog,遵循 APG Dialog (Modal) - 确认框(
Modal.confirm、info、success、warning、error,以及useModal的同名方法)的 role 为alertdialog,aria-describedby指向正文,遵循 APG Alert Dialog - aria-modal 在对话框是模态时设置为 true。模态的判定是:有遮罩(
mask),且挂载在 body 中(以实际容器判断,ConfigProvider 的getPopupContainer同样计入)或设置了maskFixed。mask={false},或遮罩限定在自定义容器内时背景保持可用,不输出 aria-modal - aria-labelledby 对应对话框标题;传入
aria-label或自定义头部时不生成该引用 - 组件版 Modal 默认不设置 aria-describedby:正文含表单、列表或多段内容时,整段正文被读出反而干扰;需要时由使用方传入
- 使用方传入的
role与全部aria-*属性落在role所在的元素上 - 关闭按钮的 aria-label 来自当前语言包(简体中文为「关闭」,英文为 'Close')
键盘和焦点
- Modal 在弹出时自动获得焦点。对话框内带
autoFocus(Vue 中为autofocus)的元素优先获得焦点,没有时默认聚焦到取消按钮,可通过在 cancelButtonProps 或 okButtonProps 传入 autoFocus 来控制该行为。keepDOM时再次打开,结果相同;keepDOM加lazyRender={false}且初始隐藏时,autoFocus元素在display: none下无法获得焦点,之后的打开落到默认按钮。 - 模态对话框关闭时,焦点自动回归到打开前元素。键盘用户可以使用
Tab键和Shift + Tab,将焦点在 Modal 内循环移动,包括 Modal 自带的关闭按钮和确定取消按钮,此时 Modal 背后的页面不可交互,也不可被 tab 聚焦。 - 非模态对话框(
mask={false},或遮罩限定在自定义容器内且未设置maskFixed)打开时同样移入焦点,但不锁定 Tab,页面其余部分保持可用。关闭时只在焦点仍在对话框内或已落到 body 时归还,用户已移到页面其他位置的焦点不动。挂载在 body 中且mask={false}的 Modal 不锁定 body 滚动。 - 修改 closeOnEsc 默认值为 true,允许用户通过键盘直接关闭 Modal 带来更好的体验
文案规范
- 命令式 Modal 与 默认 Modal 两种模态对话框的标题使用 动词 + 名词 的格式,无论是陈述句还是问句
| ✅ 推荐用法 | ❌ 不推荐用法 |
|---|---|
| Edit ticket | Edit |
| Delete form? | Are you sure you want to delete form? |
- 两种模态对话框的操作按钮在保证标题描述清楚的前提下,只需要使用标题内的动词即可
| ✅ 推荐用法 | ❌ 不推荐用法 |
|---|---|
| Edit | Edit ticket |
- 命令式 Modal 的正文规范
- 对标题进行具体的解释说明,不要重复标题的信息
- 确保用户知道在必要时如何采取行动
设计变量
| Sass 变量 | 值 | 用法 |
|---|---|---|
| $animation_duration-modal-show | 120ms | 弹窗打开-动画持续时间 |
| $animation_function-modal-show | cubic-bezier(0.215, 0.61, 0.355, 1) | 弹窗打开-过渡曲线 |
| $animation_delay-modal-show | 0ms | 弹窗打开-延迟时间 |
| $animation_duration-modal-hide | 120ms | 弹窗关闭-动画持续时间 |
| $animation_function-modal-hide | cubic-bezier(0.215, 0.61, 0.355, 1) | 弹窗关闭-过渡曲线 |
| $animation_delay-modal-hide | 0ms | 弹窗关闭-延迟时间 |
| $animation_duration-modal_mask-show | 90ms | 弹窗打开时-蒙层颜色-动画持续时间 |
| $animation_function-modal_mask-show | cubic-bezier(0.215, 0.61, 0.355, 1) | 弹窗打开时-蒙层颜色-过渡曲线 |
| $animation_delay-modal_mask-show | 0ms | 弹窗打开时-蒙层颜色-延迟时间 |
| $animation_duration-modal_mask-hide | 90ms | 弹窗关闭时-蒙层颜色-动画持续时间 |
| $animation_function-modal_mask-hide | cubic-bezier(0.215, 0.61, 0.355, 1) | 弹窗关闭时-蒙层颜色-过渡曲线 |
| $animation_delay-modal_mask-hide | 0ms | 弹窗关闭时-蒙层颜色-延迟时间 |
| $animation_transform_scale-modal_content-open | 0.7 | 弹窗打开时-缩放比例 |
| $animation_opacity-modal_content-open | 0 | 弹窗打开时-起始透明度 |
| $animation_transform_scale-modal_content-close | 0.7 | 弹窗关闭时-缩放比例 |
| $animation_opacity-modal_content-close | 0 | 弹窗关闭时-起始透明度 |
| $animation_opacity-modal_mask-open | 0 | 弹窗打开时-蒙层起始透明度 |
| $animation_opacity-modal_mask-close | 0 | 弹窗关闭时-蒙层起始透明度 |
| $color-modal-bg | var(--semi-color-bg-2) | 模态框背景颜色 |
| $color-modal_mask-bg | var(--semi-color-overlay-bg) | 模态框蒙层颜色 |
| $color-modal_main-text | var(--semi-color-text-0) | 模态框文字颜色 |
| $color-modal_info-icon | var(--semi-color-info) | 模态框信息图标颜色 |
| $color-modal_primary-icon | var(--semi-color-primary) | 模态框主要图标颜色 |
| $color-modal_success-icon | var(--semi-color-success) | 模态框成功图标颜色 |
| $color-modal_danger-icon | var(--semi-color-danger) | 模态框危险图标颜色 |
| $color-modal_warning-icon | var(--semi-color-warning) | 模态框警告图标颜色 |
| $color-modal_content-border | var(--semi-color-border) | 模态框描边颜色 |
| $color-modal_header-bg | transparent | 模态框 header 背景填充色 |
| $color-modal_footer-bg | transparent | 模态框 footer 背景填充色 |
| $spacing-modal-marginY | 80px | 模态框距容器顶部外边距 |
| $spacing-modal-marginX | auto | 模态框水平外边距(默认居中) |
| $spacing-modal_mask-top | 0 | 模态框蒙层顶部位置 |
| $spacing-modal_mask-right | 0 | 模态框蒙层右侧位置 |
| $spacing-modal_mask-bottom | 0 | 模态框蒙层底部位置 |
| $spacing-modal_mask-left | 0 | 模态框蒙层左侧位置 |
| $spacing-modal_content_withicon-marginLeft | 36px | 模态框蒙层左侧位置 |
| $spacing-modal_icon_wrapper-marginRight | $spacing-base-tight | 模态框图标右侧外边距 |
| $spacing-modal_wrap-top | 0 | |
| $spacing-modal_wrap-right | 0 | |
| $spacing-modal_wrap-bottom | 0 | |
| $spacing-modal_wrap-left | 0 | |
| $spacing-modal_title-margin | 0 | 模态框标题外边距 |
| $spacing-modal_content-paddingY | 0 | 模态框内容垂直内边距 |
| $spacing-modal_content-paddingX | 24px | 模态框内容水平内边距 |
| $spacing-modal_header-marginY | 24px | 模态框标题垂直外边距 |
| $spacing-modal_header-marginX | 0 | 模态框标题水平外边距 |
| $spacing-modal_header-paddingY | 0 | |
| $spacing-modal_header-paddingX | 0 | |
| $spacing-modal_body_wrapper-marginY | 24px | |
| $spacing-modal_body_wrapper-marginX | 0 | |
| $spacing-modal_body-margin | 0 | 模态框 body 外边距 |
| $spacing-modal_body-padding | 0 | 模态框 内容外Padding |
| $spacing-modal_footer-marginY | 24px | 模态框 footer 垂直外边距 |
| $spacing-modal_footer-marginX | 0 | 模态框 footer 水平外边距 |
| $spacing-modal_footer-paddingY | 0 | |
| $spacing-modal_footer-paddingX | 0 | |
| $spacing-modal_footer_button-marginLeft | $spacing-base-tight | 模态框 footer 按钮左侧外边距 |
| $spacing-modal_confirm_header-marginBottom | 8px | 命令式调用模态框 header 底部外边距 |
| $spacing-modal_confirm_icon_wrapper-marginRight | $spacing-base-tight | 命令式调用模态框图标右侧外边距 |
| $spacing-modal_content_fullscreen-top | 0px | 模态框内容全屏顶部位置 |
| $width-modal_title | 100% | 模态框标题宽度 |
| $width-modal_content | 100% | 模态框内容宽度 |
| $height-modal_content | max-content | 模态框内容高度 |
| $width-modal_content-border | 1px | 模态框内容描边宽度 |
| $width-modal_small | 448px | 模态框宽度 - 小 |
| $width-modal_medium | 684px | 模态框宽度 - 中 |
| $width-modal_large | 920px | 模态框宽度 - 大 |
| $width-modal_full_width | calc(100vw - 64px) | 模态框宽度 - 全屏 |
| $radius-modal_content | var(--semi-border-radius-large) | 模态框圆角大小 |
| $radius-modal_content_fullscreen | 0 | 模态框圆角大小 - 全屏 |
| $radius-modal_footer | 0 0 5px 5px | 模态框 footer 圆角大小 |
| $font-modal_header-fontSize | $font-size-regular | 模态框 title 字号 |
| $font-modal_header-fontWeight | $font-weight-bold | 模态框 title 字重 |
| $color-modal_header-border | transparent | 模态框 header 底部描边颜色 |
| $width-modal_header-border | 0 | 模态框 header 底部描边宽度 |
| $color-modal_footer-border | transparent | 模态框 footer 顶部描边颜色 |
| $width-modal_footer-border | 0 | 模态框 footer 顶部描边宽度 |
| $shadow-modal_content | var(--semi-shadow-elevated) | |
| $filter-modal_mask-bg | none | |
| $filter-modal_content-bg | none |
FAQ
-
为什么使用 LocaleProvider 后, Modal.confirm 确认、取消按钮的文本没有国际化?
命令式的 Modal 渲染在组件树之外,读不到 ConfigProvider、LocaleProvider 的配置,因此内置文本无法自动适配国际化。你可以通过
okText和cancelText这两个属性来根据 Locale 重新设置文本,也可以通过Modal.useModal()得到 modal 对象与 Holder 组件,把<Holder />放到需要读取上下文的位置,即可使 Modal 获取到对应的配置,如 ConfigProvider 或者 LocaleProvider。 -
为什么 title 和 content 的间距在命令式调用和非命令式调用下不同?
命令式调用场景下,标题和内容的相关性更强,所以用更近的距离表达这种强相关性,符合预期。用户如果不想要这种效果,可以自己做样式覆盖。