代码演示
如何引入
import { Modal } from '@fibrous/semi-ui-react';
基本
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
console.log('Ok button clicked');
};
const handleCancel = () => {
setVisible(false);
console.log('Cancel button clicked');
};
const handleAfterClose = () => {
console.log('After Close callback executed');
};
return (
<>
<Button onClick={showDialog}>打开弹窗</Button>
<Modal title="基本对话框" visible={visible} onOk={handleOk} afterClose={handleAfterClose} onCancel={handleCancel} closeOnEsc>
This is the content of a basic modal.
<br />
More content...
</Modal>
</>
);
}底部撑满
设置 footerFill 为 true 可使 Modal footer 底部按钮撑满排列
点击遮罩层不可关闭
修改 maskClosable 为 false 则不可通过点击遮罩层来关闭对话框。
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
return (
<>
<Button onClick={showDialog}>点击遮罩层不可关闭</Button>
<Modal title="对话框标题" visible={visible} onOk={handleOk} onCancel={handleCancel} maskClosable={false}>
<p>This is a modal that cannot be closed by clicking on the mask.</p>
<p>More content...</p>
</Modal>
</>
);
}自定义按钮文字
通过设置 okText 与 cancelText 属性可自定义按钮显示的文字。
注意:命令式调用的 Modal 需要通过这两个属性来设置 i18 的文本,因为我们无法修改 React 组件树,命令式调用插入的 Component 无法消费到 Locale 相关的 Context
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
return (
<>
<Button onClick={showDialog}>自定义按钮文字</Button>
<Modal title="自定义按钮文字" visible={visible} onOk={handleOk} onCancel={handleCancel} okText="Sounds great!" cancelText="No, thanks.">
<p>This is a modal with customized button texts.</p>
<p>More content...</p>
</Modal>
</>
);
}自定义按钮属性
通过设置 okButtonProps 与 cancelButtonProps 属性可自定义按钮的属性。其中的 onClick 先于内置处理调用,不会替换内置处理。
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
return (
<>
<Button onClick={showDialog}>自定义按钮属性</Button>
<Modal title="自定义按钮属性" visible={visible} onOk={handleOk} onCancel={handleCancel} okButtonProps={{ size: 'small', type: 'warning' }} cancelButtonProps={{ size: 'small', disabled: true }}>
<p>This is a modal with customized button props.</p>
<p>More content...</p>
</Modal>
</>
);
}自定义对话框头部和页脚
如果需要实现更丰富的个性化需求,可以通过 header 自定义头部,footer 自定义页脚的按钮。把 header 设为 null时则不展示头部区域;不需要显示任何按钮时,同样可以把 footer 设为 null。
自定义对话框的样式
通过设置 style 可以自定义样式及位置如 style.top,也可以通过 centered 使对话框居中显示。也可以通过设置 maskStyle 自定义遮罩样式,及 bodyStyle 自定义对话框内容样式。
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
return (
<>
<Button onClick={showDialog}>自定义对话框样式</Button>
<Modal title="自定义样式" visible={visible} onOk={handleOk} onCancel={handleCancel} centered bodyStyle={{ overflow: 'auto', height: 200 }}>
<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>
</>
);
}自定义的对话框
通过灵活使用使用 header,footer等属性可以实现一个完全自定义的对话框。
代码
import { useState } from 'react';
import { IconVigoLogo, IconSemiLogo } from '@fibrous/semi-icons-react';
import { Modal, Button, List } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleOk = () => {
setVisible(false);
};
const handleCancel = () => {
setVisible(false);
};
const data = [
{
icon: <IconSemiLogo style={{ fontSize: 48 }} />,
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 style={{ fontSize: 48 }} />,
title: 'Introducing Dark Mode',
content: 'Sample data is prepared for you to demonstrate how Integration may be useful for your team',
},
{
icon: <IconSemiLogo style={{ fontSize: 48 }} />,
title: 'New List Component',
content: 'Sample data is prepared for you to demonstrate how Integration may be useful for your team',
},
];
const btnStyle = {
width: 240,
margin: '4px 50px',
};
const footer = (
<div style={{ textAlign: 'center' }}>
<Button type="primary" theme="solid" onClick={handleOk} style={btnStyle}>
Continue
</Button>
<Button type="primary" theme="borderless" onClick={handleCancel} style={btnStyle}>
Learn more features
</Button>
</div>
);
return (
<>
<Button onClick={showDialog}>自定义对话框</Button>
<Modal header={null} visible={visible} onOk={handleOk} onCancel={handleCancel} footer={footer}>
<h3 style={{ textAlign: 'center', fontSize: 24, margin: 40 }}>Semi Design New Features</h3>
<List
dataSource={data}
split={false}
renderItem={(item) => (
<List.Item
header={item.icon}
main={
<div>
<h6 style={{ margin: 0, fontSize: 16 }}>{item.title}</h6>
<p style={{ marginTop: 4, color: 'var(--semi-color-text-1)' }}>{item.content}</p>
</div>
}
/>
)}
/>
</Modal>
</>
);
}全屏 Modal
使用 fullScreen={true} 可以开启全屏对话框
代码
import { useState } from 'react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
const onClose = () => {
setVisible(false);
};
return (
<>
<Button onClick={() => setVisible(true)}>打开全屏弹窗</Button>
<Modal title="全屏对话框标题" fullScreen visible={visible} onOk={onClose} onCancel={onClose}>
<p>This is a full screen modal</p>
<p>More content...</p>
</Modal>
</>
);
}命令式调用
使用 confirm() 可以设置一个确认框。支持各种类型的信息提示。命令式调用也可以自定义 icon , 支持 string 和 ReactNode 类型。其他 Modal 支持的 props 都可以传入。
代码
import { IconSend } from '@fibrous/semi-icons-react';
import { Modal, Button } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
function success() {
Modal.success({ title: 'This is a success message', content: 'bla bla bla...' });
}
function info() {
Modal.info({ title: 'Here is some info', content: 'bla bla bla...' });
}
function error() {
Modal.error({ title: 'Unfortunately, there is an error', content: 'bla bla bla...' });
}
function warning() {
Modal.warning({ title: 'Warning: be cautious ahead', content: 'bla bla bla...' });
}
function confirm() {
Modal.confirm({ title: 'Are you sure ?', content: 'bla bla bla...' });
}
function custom() {
Modal.info({
title: 'This is a custom modal',
content: 'bla bla bla...',
icon: <IconSend />,
cancelButtonProps: { theme: 'borderless' },
okButtonProps: { theme: 'solid' },
});
}
return (
<div>
<Button onClick={info}>Info</Button>
<br />
<br />
<Button onClick={success}>Success</Button>
<br />
<br />
<Button onClick={error} type="danger">
Error
</Button>
<br />
<br />
<Button onClick={warning} type="warning">
Warning
</Button>
<br />
<br />
<Button onClick={confirm} type="primary">
Confirm
</Button>
<br />
<br />
<Button onClick={custom}>Custom</Button>
</div>
);
}Hooks 用法
通过 Modal.useModal 创建支持读取 context 的 contextHolder。
代码
import en_GB from '@fibrous/semi-foundation/locale/source/en_GB';
import { ConfigProvider, Button, Modal } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [modal, contextHolder] = Modal.useModal();
const config = { title: 'This is a success message', content: 'Context consumer' };
return (
<ConfigProvider locale={en_GB}>
<div>
<Button
onClick={() => {
modal.confirm(config);
}}
>
Confirm Modal
</Button>
</div>
{contextHolder}
</ConfigProvider>
);
}可拖拽 Modal
通过 modalRender 自定义渲染 Modal 内容,可拖拽 Modal 通过 DragMove 组件实现。
代码
import { useState } from 'react';
import { Button, Modal, DragMove } from '@fibrous/semi-ui-react';
export default function ModalDemo() {
const [visible, setVisible] = useState(false);
return (
<div>
<Button onClick={() => setVisible(true)}>Open Modal</Button>
<Modal title="可拖拽Modal" visible={visible} centered onCancel={() => setVisible(false)} modalRender={(modal) => <DragMove positionStrategy="relative">{modal}</DragMove>}>
<p>This is the content of a basic sidesheet.</p>
<p>Here is more content...</p>
</Modal>
</div>
);
}API 参考
Modal
Props
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| afterClose | 对话框完全关闭后的回调;显示期间被卸载,或所在子树被 Activity 隐藏时也会调用一次。 | Type() => void | - |
| bodyStyle | 对话框内容区的样式。 | CSSProperties | - |
| cancelButtonProps | 取消按钮的属性,类型同 Button。打开后默认聚焦取消按钮,autoFocus 为 false 时不聚焦;onClick 先于内置的取消处理调用,不会替换内置处理。 | ButtonProps | - |
| cancelLoading | 取消按钮是否加载中;不传时跟随 onCancel 返回的 Promise,显式传入 false 关闭该行为。 | boolean | - |
| cancelText | 取消按钮文字,缺省取语言包 Modal.cancel。 | string | - |
| centered | 是否垂直居中显示。 | boolean | false |
| children | 对话框的正文。 | React.ReactNode | - |
| className | 落在 portal 内最外层元素上的类名。 | string | - |
| closable | 是否显示右上角的关闭按钮。 | boolean | true |
| closeIcon | 关闭按钮的图标;传入 null 时回落到默认图标,隐藏关闭按钮请用 closable={false}。 | ReactNode | - |
| closeOnEsc | 是否允许按 Esc 取消对话框。 | boolean | true |
| confirmLoading | 确认按钮是否加载中;不传时跟随 onOk 返回的 Promise,显式传入 false 关闭该行为。 | boolean | - |
| content | 组件版 Modal 不渲染该属性,对话框内容写在 children 中;它只用于 Modal.info 等命令式方法的选项。 | ReactNode | - |
| direction | 文字方向,覆盖 ConfigProvider 的设置;不传时跟随所在位置的 ConfigProvider。 | 'ltr' | 'rtl' | - |
| footer | 完全替换默认页脚按钮。传入 null 时隐藏页脚区域。 | ReactNode | - |
| footerFill | 默认页脚的两个按钮是否撑满排列,默认 false。 | boolean | - |
| fullScreen | 是否全屏显示,开启后 width、height 不再生效。 | boolean | false |
| getPopupContainer | 指定弹层渲染到的父级 DOM;不传时取 ConfigProvider 的 getPopupContainer,都没有时渲染到 document.body。自定义容器需要设置 position: relative,这会改变浮层的 DOM 位置,不改变视图位置。 | Type() => HTMLElement | - |
| hasCancel | 默认页脚是否显示取消按钮。 | boolean | true |
| header | 完全替换默认头部(图标、标题与关闭按钮)。传入 null 时隐藏头部区域。 | ReactNode | - |
| height | 对话框高度,数字按像素处理,字符串为合法 CSS 长度。 | string | number | - |
| icon | 标题前的图标。 | ReactNode | - |
| keepDOM | 关闭时是否保留对话框内部节点而不销毁。 | boolean | false |
| lazyRender | 配合 keepDOM 使用;为 true 时,首次显示之前不渲染对话框。 | boolean | true |
| mask | 是否显示遮罩。 | boolean | true |
| maskClosable | 是否允许点击遮罩取消对话框。 | boolean | true |
| maskFixed | 遮罩限定在自定义容器内时,是否仍以 fixed 定位覆盖整个视口并按模态处理(aria-modal、页面 inert、Tab 锁定、body 滚动锁定)。 | boolean | false |
| maskStyle | 遮罩的样式。 | CSSProperties | - |
| modalContentClass | 对话框内容元素的类名。 | string | - |
| modalRender | 自定义渲染对话框本身,参数是 role="dialog" 元素,返回值必须包含它,例如用 DragMove 包裹。 | Type(node: ReactNode) => ReactNode | - |
| motion | 是否启用进出场动画。 | boolean | true |
| okButtonProps | 确认按钮的属性,类型同 Button。autoFocus 为 true 时打开后聚焦该按钮;onClick 先于内置的确认处理调用,不会替换内置处理。 | ButtonProps | - |
| okText | 确认按钮文字,缺省取语言包 Modal.confirm。 | string | - |
| okType | 确认按钮的类型,同 Button 的 type。 | OKType | "primary" |
| onCancel | 取消按钮、关闭按钮、遮罩和 Esc 触发;按 Esc 时参数为原生 KeyboardEvent。返回 Promise 时取消按钮保持加载直到落定;对话框不会自行关闭,由使用方把 visible 设为 false。 | Type(e: React.MouseEvent | KeyboardEvent) => void | Promise<any> | - |
| onOk | 点击确认按钮时调用,参数是点击事件;返回 Promise 时确认按钮保持加载直到落定。对话框不会自行关闭,由使用方把 visible 设为 false。 | Type(e: React.MouseEvent) => void | Promise<any> | - |
| preventScroll | 组件内部调用 focus 时是否阻止浏览器滚动到被聚焦元素,不影响使用方自己的 focus 调用;未设置时聚焦会滚动到该元素。 | boolean | - |
| ref | 接收 portal 内最外层 div 元素的引用,没有渲染内容时为 null。 | TypeReact.Ref<HTMLDivElement> | - |
| role | 对话框元素的 role,默认 dialog;命令式方法使用 alertdialog。 | 'dialog' | 'alertdialog' | - |
| size | 对话框宽度档位:small 为 448px,medium 为 684px,large 为 920px,full-width 为 100vw - 64px。 | Size | "small" |
| style | 落在 .semi-modal 对话框盒子上的样式。 | CSSProperties | - |
| title | 对话框标题;未传入 aria-label 或自定义 header 时,标题用于命名对话框。 | ReactNode | - |
| visible | 对话框是否可见,由使用方控制。 | boolean | false |
| width | 对话框宽度,数字按像素处理,字符串为合法 CSS 长度;不传时由 size 决定。 | string | number | - |
| zIndex | 弹层外层的 z-index。 | number | 1000 |
role 与全部 aria-* 属性落在 role="dialog" 元素上,style 落在 .semi-modal 对话框盒子上,className 与其他原生属性(如 id、data-*)落在 portal 内最外层元素上。
组件版 Modal 不渲染 content,对话框内容请写在 children 中;content 只用于下面的命令式方法。
Modal.method()
Modal.infoModal.successModal.errorModal.warningModal.confirm
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| bodyStyle | 对话框内容的样式 | CSSProperties | 无 |
| cancelButtonProps | 取消按钮的 props | ButtonProps | 无 |
| cancelText | 取消按钮的文字 | string | 无 |
| centered | 是否居中显示 | boolean | false |
| className | 可用于设置样式类名 | string | 无 |
| closable | 是否显示右上角的关闭按钮 | boolean | true |
| confirmLoading | 确认按钮 loading;未设置时跟随 onOk 返回 Promise 的 pending 状态,显式传 false 关闭该行为 | boolean | - |
| content | 对话框内容 | ReactNode | 无 |
| footer | 对话框底部 | ReactNode | 无 |
| footerFill | 底部按钮是否撑满 | boolean | false |
| header | 对话框头部 | ReactNode | 无 |
| height | 高度 | string | number | 无 |
| icon | 自定义 icon | ReactNode | - |
| mask | 是否显示遮罩 | boolean | true |
| maskClosable | 是否允许通过点击遮罩来关闭对话框 | boolean | true |
| maskStyle | 遮罩的样式 | CSSProperties | 无 |
| modalContentClass | 可用于设置对话框内容的样式类名 | string | 无 |
| modalRender | 自定义渲染 Modal | (modal: ReactNode) => ReactNode | - |
| motion | 动画效果开关,update 中修改同样生效 | boolean | true |
| okButtonProps | 确认按钮的 props,其中的 onClick 先于内置处理调用,不会替换内置处理 | ButtonProps | 无 |
| okText | 确认按钮的文字 | string | 无 |
| okType | 确认按钮的类型 | string | primary |
| style | 可用于设置样式 | CSSProperties | 无 |
| title | 对话框的标题 | ReactNode | 无 |
| width | 宽度,未设置时由 size 决定(small 为 448) | string | number | - |
| zIndex | 遮罩的 z-index 值 | number | 1000 |
| onCancel | 取消回调,返回 promise 时 resolve 后自动关闭;按 Esc 关闭时参数为原生 KeyboardEvent | (e: React.MouseEvent | KeyboardEvent) => void | Promise<any> | 无 |
| onOk | 点击确定回调,参数是点击事件,返回 promise 时 resolve 后自动关闭 | (e: any) => void | Promise<any> | 无 |
以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。update 接收与以上函数相同的属性(ModalProps),合并到当前配置,不接收 type。
const modal = Modal.info();
modal.update({
title: '更新的标题',
content: '更新的内容',
});
modal.destroy();
Modal.destroyAll
使用 Modal.destroyAll() 可以销毁命令式及以上.info()等创建的弹窗。
Modal.useModal当你需要使用 Context 时,可以通过 Modal.useModal 创建一个 contextHolder 插入相应的节点中。此时通过 hooks 创建的 Modal 将会得到 contextHolder 所在位置的所有上下文。创建的 modal 对象拥有与 Modal.method 相同的创建通知方法。
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 使用 Portal 将浮层节点插入到 DOM 树中。但这个操作仅能改变节点在 DOM 树中的位置,无法改变节点在 React 节点树中的位置,LocalProvider是基于 Context 机制传递的,必须是从属的 React 子结点才可消费到 Local 相关 Context。因此命令式的 Modal 的内置文本无法自动适配国际化。你可以通过
okText和cancelText这两个属性来根据 Locale 重新设置 i18 的文本。
你也可以通过 Modal.useModal 方法来返回 modal 实体以及 contextHolder 节点。将 contextHolder 插入到你需要获取 context 位置,即可使 Modal 获取到对应的 Context,如 ConfigProvider 或者 LocaleProvider 的配置。 -
为什么 title 和 content 的间距在命令式调用和非命令式调用下不同?
命令式调用场景下,标题和内容的相关性更强,所以用更近的距离表达这种强相关性,符合预期。用户如果不想要这种效果,可以自己做样式覆盖。