Dialog 对话框
在保留当前页面状态的情况下,告知用户并承载相关操作。
基础用法
Dialog 弹出一个对话框,适合需要定制性更大的场景。
需要设置 model-value / v-model 属性,它接收 Boolean,当为 true 时显示 Dialog。 Dialog 分为两个部分:body 和 footer,footer 需要具名为 footer 的 slot。 title 属性用于定义标题,它是可选的,默认值为空。最后,本例还展示了 before-close 的用法。
Click to open the Dialog
export function DialogBasicUsage() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Click to open the Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} title="Tips" width={500} beforeClose={(done) => { MessageBox.confirm("Are you sure to close this dialog?") .then(() => done()) .catch(() => {}); }} footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>This is a message</span> </ElDialog> </> ); } before-close 只会在用户点击关闭按钮或者对话框的遮罩区域时被调用。如果你在 footer 具名 slot 里添加了用于关闭 Dialog 的按钮,那么可以在按钮的点击回调函数里加入 before-close 的相关逻辑。
自定义内容
对话框的内容可以是任何东西,甚至是一个表格或表单。此示例显示如何在 Dialog 中使用 Element Plus 的表格和表单。
Open a Table nested Dialog Open a Form nested Dialog
export function DialogCustomizationContent() { const [tableVisible, setTableVisible] = useState(false); const [formVisible, setFormVisible] = useState(false); const [form, setForm] = useState({ name: "", region: "" }); return ( <> <div className={styles.row}> <ElButton plain onClick={() => setTableVisible(true)}> Open a Table nested Dialog </ElButton> <ElButton plain onClick={() => setFormVisible(true)}> Open a Form nested Dialog </ElButton> </div> <ElDialog visible={tableVisible} onVisibleChange={setTableVisible} title="Shipping address" width={800}> <ElTable data={gridData}> <ElTableColumn property="date" label="Date" width={150} /> <ElTableColumn property="name" label="Name" width={200} /> <ElTableColumn property="address" label="Address" /> </ElTable> </ElDialog> <ElDialog visible={formVisible} onVisibleChange={setFormVisible} title="Shipping address" width={500} footer={ <Footer cancel={() => setFormVisible(false)} confirm={() => setFormVisible(false)} /> } > <div style={{ display: "grid", gap: "0.875rem" }}> <label style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}> <span style={{ width: 140 }}>Promotion name</span> <ElInput value={form.name} onChange={(value) => setForm((current) => ({ ...current, name: value }))} /> </label> <label style={{ display: "flex", alignItems: "center", gap: "0.75rem" }}> <span style={{ width: 140 }}>Zones</span> <ElSelect value={form.region} onChange={(value) => setForm((current) => ({ ...current, region: String(value ?? "") })) } placeholder="Please select a zone" options={[ { value: "shanghai", label: "Zone No.1" }, { value: "beijing", label: "Zone No.2" }, ]} style={{ flex: 1 }} /> </label> </div> </ElDialog> </> ); } 自定义头部
header 可用于自定义显示标题的区域。为了保持可用性,除了使用此插槽外,使用 title 属性,或使用 titleId 插槽属性来指定哪些元素应该读取为对话框标题。
Open Dialog with customized header
export function DialogCustomizationHeader() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Open Dialog with customized header </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} showClose={false} width={500} header={({ close, titleId, titleClass }) => ( <div style={{ display: "flex", flexDirection: "row", justifyContent: "space-between", gap: 16, }} > <h4 id={titleId} className={titleClass} style={{ margin: 0 }}> This is a custom header! </h4> <ElButton type="danger" onClick={close}> <CircleCloseFilled style={{ marginRight: 4 }} /> Close </ElButton> </div> )} > This is dialog content. </ElDialog> </> ); } 嵌套的对话框
如果需要在一个 Dialog 内部嵌套另一个 Dialog,需要使用 append-to-body 属性。
通常我们不建议使用嵌套对话框。如果你需要在页面上呈现多个对话框,你可以简单地打平它们,以便它们彼此之间是平级关系。如果必须要在一个对话框内展示另一个对话框,可以将内部嵌套的对话框属性 append-to-body 设置为 true,嵌套的对话框将附加到 body 而不是其父节点,这样两个对话框都可以被正确地渲染。
Open the outer Dialog
export function DialogNestedDialog() { const [outerVisible, setOuterVisible] = useState(false); const [innerVisible, setInnerVisible] = useState(false); return ( <> <ElButton plain onClick={() => setOuterVisible(true)}> Open the outer Dialog </ElButton> <ElDialog visible={outerVisible} onVisibleChange={setOuterVisible} title="Outer Dialog" width={800} footer={ <Footer cancel={() => setOuterVisible(false)} confirm={() => setInnerVisible(true)} confirmText="Open the inner Dialog" /> } > <span>This is the outer Dialog</span> <ElDialog visible={innerVisible} onVisibleChange={setInnerVisible} width={500} title="Inner Dialog" appendToBody > <span>This is the inner Dialog</span> </ElDialog> </ElDialog> </> ); } 内容居中
对话框的内容可以居中。
将center设置为true即可使标题和底部居中。 center仅影响标题和底部区域。 Dialog 的内容是任意的,在一些情况下,内容并不适合居中布局。如果需要内容也水平居中,请自行为其添加 CSS 样式。
Click to open the Dialog
export function DialogCenteredContent() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Click to open the Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} title="Warning" width={500} center footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span> It should be noted that the content will not be aligned in center by default </span> </ElDialog> </> ); } Dialog 的内容是懒渲染的——在被第一次打开之前,传入的默认 slot 不会被立即渲染到 DOM 上。因此,如果需要执行 DOM 操作,或通过 ref 获取相应组件,请在 open 事件回调中进行。
居中对话框
从屏幕中心打开对话框。
设置 align-center 为 true 使对话框水平垂直居中。由于对话框垂直居中在弹性盒子中,所以top属性将不起作用。
Click to open the Dialog
export function DialogAlignCenter() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Click to open the Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} title="Warning" width={500} alignCenter footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>Open the dialog from the center from the screen</span> </ElDialog> </> ); } 关闭时销毁
启用此功能时,默认栏位下的内容将使用 v-if 指令销毁。当出现性能问题时,可以启用此功能。
需要注意的是,当这个属性被启用时,在 transition.beforeEnter 事件卸载前,除了 overlay、header (可选)与footer(可选) ,Dialog 内不会有其它任何其它的 DOM 节点存在。
Click to open Dialog
export function DialogDestroyOnClose() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Click to open Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} title="Notice" width={500} destroyOnClose center footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span> Notice: before the dialog is opened for the first time, this node and the one below will not be rendered. </span> <div> <strong>Extra content (Not rendered)</strong> </div> </ElDialog> </> ); } 可拖拽对话框
试着拖动一下header部分吧
设置draggable属性为true以做到拖拽设置 overflow 2.5.4 为 true 可以让拖拽范围超出可视区。
Open a draggable Dialog Open a overflow draggable Dialog Open a custom dragging style Dialog
export function DialogDraggableDialog() { const [visible, setVisible] = useState(false); const [overflowVisible, setOverflowVisible] = useState(false); const [customVisible, setCustomVisible] = useState(false); return ( <> <div className={styles.rowGap1}> <ElButton plain onClick={() => setVisible(true)}> Open a draggable Dialog </ElButton> <ElButton plain onClick={() => setOverflowVisible(true)}> Open a overflow draggable Dialog </ElButton> <ElButton plain onClick={() => setCustomVisible(true)}> Open a custom dragging style Dialog </ElButton> </div> <ElDialog visible={visible} onVisibleChange={setVisible} title="Tips" width={500} draggable footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>It's a draggable Dialog</span> </ElDialog> <ElDialog visible={overflowVisible} onVisibleChange={setOverflowVisible} title="Tips" width={500} draggable overflow footer={ <Footer cancel={() => setOverflowVisible(false)} confirm={() => setOverflowVisible(false)} /> } > <span>It's a overflow draggable Dialog</span> </ElDialog> <ElDialog visible={customVisible} onVisibleChange={setCustomVisible} className="custom-dragging-style" title="Custom Dragging Style" width={500} draggable footer={ <Footer cancel={() => setCustomVisible(false)} confirm={() => setCustomVisible(false)} /> } > <span> This dialog has custom dragging styles. Try dragging it to see the effects! </span> </ElDialog> </> ); } 当 modal 的值为 false 时,请一定要确保 append-to-body 属性为 true ,由于 Dialog 使用 position: relative 定位,当外层的遮罩层被移除时,Dialog 则会根据当前 DOM 上的祖先节点来定位,因此可能造成定位问题。
全屏
设置 fullscreen 属性来打开全屏对话框。
Open the fullscreen Dialog
export function DialogFullscreen() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Open the fullscreen Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} fullscreen footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>It's a fullscreen Dialog</span> </ElDialog> </> ); } 如果 fullscreen 为 true,则 width、top 和 draggable 属性无效。
模态框
将 modal 设置为 false 会隐藏对话框的模态(覆盖层)。
从版本 2.10.5 起,新增了 modal-penetrable属性,该属性可设置为“可穿透”(即允许穿透)。
Open the modal Dialog
export function DialogModal() { const [visible, setVisible] = useState(false); return ( <> <ElButton plain onClick={() => setVisible(true)}> Open the modal Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} modal={false} modalPenetrable footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>It's a modal Dialog</span> </ElDialog> </> ); } 自定义动画 2.10.5
通过 transition 属性自定义对话框动画,该属性可以接受以下任意一种值:
示例包括缩放(scale)、滑动(slide)、淡入淡出(fade)、弹跳(bounce)动画,以及带有自定义事件处理器的基于对象的配置。
Default Scale Slide Bounce Object Config
export function DialogCustomAnimation() { const [visible, setVisible] = useState(false); const [animation, setAnimation] = useState("fade"); const [isObjectConfig, setIsObjectConfig] = useState(false); const open = (type: string) => { setAnimation(type); setIsObjectConfig(false); setVisible(true); }; const openWithObject = () => { setAnimation("object-config"); setIsObjectConfig(true); setVisible(true); }; const transition = isObjectConfig ? "dialog-custom-object" : `dialog-${animation}`; return ( <> <div> <ElButton plain onClick={() => open("fade")}> Default </ElButton> <ElButton plain onClick={() => open("scale")}> Scale </ElButton> <ElButton plain onClick={() => open("slide")}> Slide </ElButton> <ElButton plain onClick={() => open("bounce")}> Bounce </ElButton> <ElButton plain onClick={openWithObject}> Object Config </ElButton> </div> <ElDialog visible={visible} onVisibleChange={setVisible} className="custom-transition-dialog" title={`${animation} Animation Dialog`} width="30%" transition={transition} footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <div> <p> Current animation: <strong>{animation}</strong> </p> <p> This dialog demonstrates the {animation} animation effect. </p> {isObjectConfig && ( <p> <strong>Using object configuration:</strong> <br /> <code className={styles.code}> {JSON.stringify(objectTransitionConfig, null, 2)} </code> </p> )} </div> </ElDialog> </> ); } Events
打开开发者控制台(ctrl + shift + J),查看事件的顺序。
Open the event Dialog
export function DialogEvents() { const [visible, setVisible] = useState(false); const [logs, setLogs] = useState<string[]>([]); const log = (name: string) => setLogs((current) => [...current, name]); return ( <> <ElButton plain onClick={() => setVisible(true)}> Open the event Dialog </ElButton> <ElDialog visible={visible} onVisibleChange={setVisible} beforeClose={(done) => { log("before-close"); done(); }} onOpen={() => log("open")} onOpened={() => log("opened")} onClose={() => log("close")} onClosed={() => log("closed")} onOpenAutoFocus={() => log("open-auto-focus")} onCloseAutoFocus={() => log("close-auto-focus")} footer={ <Footer cancel={() => setVisible(false)} confirm={() => setVisible(false)} /> } > <span>It's a event Dialog</span> <div style={{ marginTop: 12, fontSize: 12, color: "var(--el-text-color-secondary)" }}> {logs.length > 0 ? logs.join(" → ") : "No events yet"} </div> </ElDialog> </> ); } API
Attributes
属性名 说明 类型 默认 visible / model-value 是否显示 Dialog booleanfalse title Dialog 对话框的标题,也可通过 header 插槽传入 string'' width 对话框的宽度,默认值为 50% string / number'' fullscreen 是否为全屏 Dialog booleanfalse top dialog CSS 中的 margin-top 值,默认为 15vh string'' modal 是否需要遮罩层 booleantrue modalPenetrable 2.10.5 是否允许穿透遮罩层。modal 属性必须为 false。 booleanfalse modalClass 遮罩的自定义类名 string— headerClass 2.9.3 header 部分的自定义 class 名 string— bodyClass 2.9.3 body 部分的自定义 class 名 string— footerClass 2.9.3 footer 部分的自定义 class 名 string— appendToBody Dialog 自身是否插入至 body 元素上。嵌套的 Dialog 必须指定该属性并赋值为 true booleanfalse appendTo 2.4.3 Dialog 挂载到哪个 DOM 元素,将覆盖 appendToBody CSSSelector / HTMLElementbody lockScroll 是否在 Dialog 出现时将 body 滚动锁定 booleantrue openDelay dialog 打开的延时时间,单位毫秒 number0 closeDelay dialog 关闭的延时时间,单位毫秒 number0 closeOnClickModal 是否可以通过点击 modal 关闭 Dialog booleantrue closeOnPressEscape 是否可以通过按下 ESC 关闭 Dialog booleantrue showClose 是否显示关闭按钮 booleantrue beforeClose 关闭前的回调,会暂停 Dialog 的关闭。回调函数内执行 done 参数方法的时候才是真正关闭对话框的时候。 Function— draggable 为 Dialog 启用可拖拽功能 booleanfalse overflow 2.5.4 拖动范围可以超出可视区 booleanfalse center 是否让 Dialog 的 header 和 footer 部分居中排列 booleanfalse alignCenter 2.2.16 是否水平垂直对齐对话框 booleanfalse destroyOnClose 当关闭 Dialog 时,销毁其中的元素 booleanfalse closeIcon 自定义关闭图标,默认 Close string / Component— zIndex 和原生的 CSS 的 z-index 相同,改变 z 轴的顺序 number— headerAriaLevel a11y header 的 aria-level 属性 string2 transition 2.10.5 对话框动画的自定义过渡配置。可以是一个字符串(过渡名称),也可以是一个包含过渡属性的对象。 string / objectdialog-fade className Dialog 的自定义类名 string''
custom-class 已被弃用,之后将会在 2.4.0 移除,请使用 class。
Slots
插槽名 说明 default 对话框的默认内容 header 对话框标题的内容;会替换标题部分,但不会移除关闭按钮。 footer Dialog 按钮操作区的内容 title deprecated 与 header 作用相同,请使用 header
title 已被弃用,并将在 3.0.0 版本中移除,请使用 header 代替。
事件
名称 详情 类型 open Dialog 打开的回调 Functionopened Dialog 打开动画结束时的回调 Functionclose Dialog 关闭的回调 Functionclosed Dialog 关闭动画结束时的回调 FunctionopenAutoFocus 输入焦点聚焦在 Dialog 内容时的回调 FunctioncloseAutoFocus 输入焦点从 Dialog 内容失焦时的回调 Function
Exposes
名称 详情 类型 resetPosition 2.8.1 重置位置 FunctionhandleClose 2.9.8 关闭对话框 Function
FAQ
在 SFC 文件中使用对话框,scope 样式不会生效
典型议题:#10515
PS:既然对话框是使用 Teleport 渲染的,建议在全局范围写入根节点的样式。
当对话框被显示及隐藏时,页面元素会来回移动(抖动)
典型议题:#10481
PS:建议将滚动区域放置在一个挂载的节点下,并对 body 使用 overflow: hidden 样式。