尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Vue3对话框(Dialog)

Vue3对话框(Dialog) Vue2对话框Dialog可自定义设置以下属性对话框宽度width类型string | number单位 px默认 520对话框高度height类型string | number单位 px默认 auto自适应内容高度标题title类型string | slot默认 undefined自定义标题样式titleStyle类型CSSProperties默认 {}内容content类型string | slot默认 undefined自定义内容样式contentStyle类型CSSProperties默认 {}自定义 body 类名bodyClass类型string默认 undefined自定义 body 样式bodyStyle类型CSSProperties默认 {}Scrollbar 组件属性配置scrollbarProps用于设置内容滚动条的样式参考 Scrollbar Props类型object默认 {}取消按钮文字cancelText类型string默认 取消取消按钮 props 配置cancelProps参考 Button 组件 Props类型object默认 {}确定按钮文字okText类型string默认 确认确定按钮类型okType类型primary | danger默认 primary确认按钮 props 配置okProps优先级高于 okType参考 Button 组件 Props类型object默认 {}是否显示底部按钮footer类型boolean | slot默认 true关闭时是否销毁 Dialog 里的子元素destroyOnClose类型boolean默认 false是否允许切换全屏switchFullscreen允许后右上角会出现一个切换按钮类型boolean默认 false是否水平垂直居中centered否则固定高度水平居中类型boolean默认 false固定高度水平居中时距顶部高度top仅当 centered: false 时生效单位 px类型string | number默认 100对话框动画出现的位置transformOrigin类型mouse | center默认 mouse确定按钮加载中confirmLoading类型boolean默认 false是否在打开对话框时禁用背景滚动blockScroll类型boolean默认 true是否支持键盘 esc 关闭keyboard类型boolean默认 true点击蒙层是否允许关闭maskClosable类型boolean默认 true自定义蒙层样式maskStyle类型CSSProperties默认 {}对话框是否可见v-model:open类型boolean默认 false效果如下图在线预览①创建对话框组件Dialog.vue其中引入使用了以下组件与工具函数Vue3滚动条ScrollbarVue3按钮Button否支持事件监听器选项 useOptionsSupportedscript setup langts import { ref, computed, watch, watchEffect, nextTick, onMounted, onUnmounted } from vue import type { CSSProperties } from vue import Scrollbar from components/scrollbar import Button from components/button import { useOptionsSupported } from components/utils export interface Props { width?: string | number // 对话框宽度单位 px height?: string | number // 对话框高度单位 px默认自适应内容高度 title?: string // 标题 string | slot titleStyle?: CSSProperties // 自定义标题样式 content?: string // 内容 string | slot contentStyle?: CSSProperties // 自定义内容样式 bodyClass?: string // 自定义 body 类名 bodyStyle?: CSSProperties // 自定义 body 样式 scrollbarProps?: object // Scrollbar 组件属性配置用于设置内容滚动条的样式 cancelText?: string // 取消按钮文字 cancelProps?: object // 取消按钮 props 配置参考 Button 组件 Props okText?: string // 确定按钮文字 okType?: primary | danger // 确定按钮类型 okProps?: object // 确认按钮 props 配置优先级高于 okType参考 Button 组件 Props footer?: boolean // 是否显示底部按钮 boolean | slot destroyOnClose?: boolean // 关闭时是否销毁 Dialog 里的子元素 switchFullscreen?: boolean // 是否允许切换全屏允许后右上角会出现一个切换按钮 centered?: boolean // 是否水平垂直居中否则固定高度水平居中 top?: string | number // 固定高度水平居中时距顶部高度仅当 centered: false 时生效单位 px transformOrigin?: mouse | center // 对话框动画出现的位置 confirmLoading?: boolean // 确定按钮 loading blockScroll?: boolean // 是否在打开对话框时禁用背景滚动 keyboard?: boolean // 是否支持键盘 esc 关闭 maskClosable?: boolean // 点击蒙层是否允许关闭 maskStyle?: CSSProperties // 自定义蒙层样式 open?: boolean // 对话框是否可见 } const props withDefaults(definePropsProps(), { width: 520, height: auto, title: undefined, titleStyle: () ({}), content: undefined, contentStyle: () ({}), bodyClass: undefined, bodyStyle: () ({}), scrollbarProps: () ({}), cancelText: 取消, cancelProps: () ({}), okText: 确定, okType: primary, okProps: () ({}), footer: true, destroyOnClose: false, switchFullscreen: false, centered: false, top: 100, transformOrigin: mouse, confirmLoading: false, blockScroll: true, keyboard: true, maskClosable: true, maskStyle: () ({}), open: false }) const dialogRef ref() // dialog DOM 引用 const mousePosition ref{ x: number; y: number } | null(null) // 鼠标点击位置 const dialogOpen refboolean() const showDialogWrap refboolean() const dialogTransformOrigin refstring(50% 50%) const fullscreen refboolean(false) const { isSupported: captureSupported } useOptionsSupported(capture) const emits defineEmits([update:open, cancel, ok]) const dialogWidth computed(() { if (typeof props.width number) { return ${props.width}px } return props.width }) const dialogHeight computed(() { if (typeof props.height number) { return ${props.height}px } return props.height }) const dialogTop computed(() { if (typeof props.top number) { return ${props.top}px } return props.top }) const dialogStyle computed(() { if (fullscreen.value) { if (props.transformOrigin mouse) { return { width: 100%, transformOrigin: ${mousePosition.value?.x}px ${mousePosition.value?.y}px } as CSSProperties } else { return { width: 100%, transformOrigin: dialogTransformOrigin.value } as CSSProperties } } else { if (props.centered) { return { width: dialogWidth.value, transformOrigin: dialogTransformOrigin.value } as CSSProperties } else { return { width: dialogWidth.value, transformOrigin: dialogTransformOrigin.value, top: dialogTop.value } as CSSProperties } } }) const dialogBodyStyle computed(() { if (fullscreen.value) { return { height: 100vh, ...props.bodyStyle } as CSSProperties } else { return { height: dialogHeight.value, ...props.bodyStyle } as CSSProperties } }) watch( dialogOpen, async (to) { if (to) { await nextTick() dialogRef.value.focus() if (props.blockScroll) { // 锁定滚动 document.documentElement.style.overflowY hidden document.body.style.overflowY hidden } } else { if (props.blockScroll) { // 解锁滚动 document.documentElement.style.removeProperty(overflow-y) document.body.style.removeProperty(overflow-y) } } }, { immediate: true } ) watchEffect(() { dialogOpen.value props.open }) onMounted(() { document.addEventListener(click, getClickPosition, captureSupported.value ? { capture: true } : true) // 事件在捕获阶段执行 }) onUnmounted(() { document.removeEventListener(click, getClickPosition, captureSupported.value ? { capture: true } : true) }) function getClickPosition(e: MouseEvent) { if (!dialogOpen.value) { mousePosition.value { x: e.clientX, // 相对于浏览器视口左上角的 X 坐标不页面滚动而改变 y: e.clientY // 相对于浏览器视口左上角的 Y 坐标不页面滚动而改变 } } } async function onBeforeEnter(el: Element) { showDialogWrap.value true await nextTick() if (props.transformOrigin mouse mousePosition.value) { const rect el.getBoundingClientRect() dialogTransformOrigin.value ${mousePosition.value.x - rect.left}px ${mousePosition.value.y - rect.top}px } else { dialogTransformOrigin.value 50% 50% } } function onBeforeLeave(el: Element) { if (props.transformOrigin mouse mousePosition.value) { const rect el.getBoundingClientRect() dialogTransformOrigin.value ${mousePosition.value.x - rect.left}px ${mousePosition.value.y - rect.top}px } else { dialogTransformOrigin.value 50% 50% } } function onAfterLeave() { showDialogWrap.value false // 重置全屏显示 fullscreen.value false } function onFullScreen() { fullscreen.value !fullscreen.value } function onCancel() { dialogOpen.value false emits(update:open, false) emits(cancel) } function onOk() { emits(ok) } /script template div classdialog-root Transition namefade div v-showdialogOpen classdialog-mask :stylemaskStyle/div /Transition div v-showshowDialogWrap tabindex-1 refdialogRef classdialog-wrap :class{ flex-centered: centered } click.selfprops.maskClosable ? onCancel() : () false keydown.escprops.keyboard ? onCancel() : () false Transition namezoom enter-from-classzoom-enter enter-active-classzoom-enter enter-to-classzoom-enter zoom-enter-active leave-from-classzoom-leave leave-active-classzoom-leave zoom-leave-active leave-to-classzoom-leave zoom-leave-active before-enteronBeforeEnter before-leaveonBeforeLeave after-leaveonAfterLeave div v-showdialogOpen classdialog-container :class{ dialog-with-fullscreen: fullscreen } :styledialogStyle div v-if!destroyOnClose classdialog-body-wrap :classbodyClass :styledialogBodyStyle div classdialog-header :class{ header-with-switch: switchFullscreen } :styletitleStyle slot nametitle{{ title }}/slot /div span v-ifswitchFullscreen classfullscreen-action clickonFullScreen svg v-show!fullscreen focusablefalse >script setup langts import Dialog from ./Dialog.vue import { ref } from vue const open1 ref(false) const open2 ref(false) const open3 ref(false) const open4 ref(false) const open5 ref(false) const open6 ref(false) const open7 ref(false) const open8 ref(false) const open9 ref(false) const open10 ref(false) const open11 ref(false) const open12 ref(false) const open13 ref(false) const confirmLoading ref(false) function onCancel() { // 点击蒙层或 Esc 键或右上角叉或取消按钮的回调 console.log(cancel) } function onOk() { // 点击确定的回调 open1.value false open2.value false open3.value false open4.value false open5.value false open6.value false open7.value false open8.value false open9.value false open10.value false open11.value false open12.value false console.log(ok) } function handleCancel() { // 点击蒙层或 Esc 键或右上角叉或取消按钮的回调 console.log(cancel) } function handleOk() { // 点击确定回调 confirmLoading.value true // 开启加载状态 setTimeout(() { confirmLoading.value false open13.value false console.log(ok) }, 2000) } /script template div h1{{ $route.name }} {{ $route.meta.title }}/h1 h2 classmt30 mb10基本使用/h2 Button typeprimary clickopen1 trueOpen Dialog/Button Dialog v-model:openopen1 titleTitle cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10自定义宽高/h2 Button typeprimary clickopen2 trueOpen Dialog/Button Dialog v-model:openopen2 :width480 :height200 cancelonCancel okonOk template #titleTitle/template pSome contents.../p pSome contents.../p pSome contents.../p pSome contents.../p pSome contents.../p pSome contents.../p /Dialog h2 classmt30 mb10自定义样式/h2 Space Button typeprimary clickopen3 trueCustom Body Class Dialog/Button Button typeprimary clickopen4 trueCustom Body Mask Style Dialog/Button Button typeprimary clickopen5 trueCustom Title Content Style Dialog/Button /Space Dialog v-model:openopen3 titleTitle body-classcustom-class cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog Dialog v-model:openopen4 titleTitle :body-style{ padding: 24px, borderRadius: 16px } :mask-style{ backgroundColor: rgba(0, 0, 0, 0.6) } cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog Dialog v-model:openopen5 titleTitle :title-style{ fontSize: 18px, color: #d4380d } :content-style{ fontSize: 16px, color: #d4380d } cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10自定义按钮/h2 Button typeprimary clickopen6 trueCustom Btns Dialog/Button Dialog v-model:openopen6 titleTitle cancel-textReturn :cancel-props{ type: danger, ghost: true } ok-textSubmit :ok-props{ type: primary, ghost: true } cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10隐藏底部按钮/h2 Button typeprimary clickopen7 trueOpen Dialog/Button Dialog v-model:openopen7 titleTitle :footerfalse cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10切换全屏/h2 Button typeprimary clickopen8 trueOpen Dialog/Button Dialog v-model:openopen8 titleTitle switch-fullscreen cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10自定义位置/h2 Space Button typeprimary clickopen9 trueFixed Top Number Dialog/Button Button typeprimary clickopen10 trueFixed Top Percent Dialog/Button Button typeprimary clickopen11 trueVertically Centered Dialog/Button /Space Dialog v-model:openopen9 title60px Top Title :top60 cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog Dialog v-model:openopen10 title20% Top Title top20% cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog Dialog v-model:openopen11 titleCentered Title centered cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10动画出现位置/h2 Button typeprimary clickopen12 trueTransform Origin Center Dialog/Button Dialog v-model:openopen12 titleTitle transform-origincenter cancelonCancel okonOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog h2 classmt30 mb10异步延迟关闭/h2 Button typeprimary clickopen13 trueDelayed Close Dialog/Button Dialog v-model:openopen13 titleTitle :confirm-loadingconfirmLoading cancelhandleCancel okhandleOk pBla bla .../p pBla bla .../p pBla bla .../p /Dialog /div /template style langless scoped :deep(.custom-class) { .dialog-header { color: #ff6900 !important; } .dialog-content { color: #ff6900 !important; } } /style
返回列表