赞
踩
可自定义设置以下属性:
标题(title),类型:string | slot,默认 '提示'
内容(content),类型:string | slot,默认 ''
宽度(width),类型:number,单位px,默认 540px
高度(height),类型:number|string,默认 'auto',自适应内容高度
是否允许切换全屏(switchFullscreen),允许后右上角会出现一个按钮,类型:boolean,默认 false
取消按钮文字(cancelText),类型:string,默认 '取消'
确认按钮文字(okText),类型:string,默认 '确认'
是否显示底部按钮(footer),类型:boolean,默认 false
是否水平垂直居中(center),类型:boolean,默认 true,(false时是固定高度水平居中)
固定高度水平居中时,距顶部高度(top),类型:number,默认 100px
加载中(loading),类型:boolean,默认 false
对话框 body 样式(bodyStyle),类型:CSSProperties,默认 {}
对话框是否可见(visible),类型:boolean,默认 false
效果如下图:在线预览(整体样式模仿ant-design-vue Modal,同时阴影覆盖浏览器窗口)
其中引入使用了Vue3加载中(Spin)、Vue3按钮(Button)
①创建对话框组件Dialog.vue:
- <script setup lang="ts">
- import Spin from '../spin'
- import Button from '../button'
- import { ref, watch, computed } from 'vue'
- import type { CSSProperties } from 'vue'
- interface Props {
- title?: string // 标题 string | slot
- content?: string // 内容 string | slot
- width?: number // 宽度,单位px
- height?: number|string // 高度,单位px,默认auto,自适应内容高度
- switchFullscreen?: boolean // 是否允许切换全屏,允许后右上角会出现一个按钮
- cancelText?: string // 取消按钮文字
- okText?: string // 确定按钮文字
- footer?: boolean // 是否显示底部按钮,默认不显示
- center?: boolean // 水平垂直居中:true 固定高度水平居中:false
- top?: number // 固定高度水平居中时,距顶部高度
- loading?: boolean // 加载中
- bodyStyle?: CSSProperties // 对话框 body 样式
- visible?: boolean // 是否可见
- }
- const props = withDefaults(defineProps<Props>(), {
- title: '提示',
- content: '',
- width: 540,
- height: 'auto',
- switchFullscreen: false,
- cancelText: '取消',
- okText: '确定',
- footer: false,
- center: true,
- top: 100,
- loading: false,
- bodyStyle: () => ({}),
- visible: false
- })
- const fullScreen = ref(false)
- const dialogHeight = computed(() => {
- if (typeof props.height === 'number') {
- return props.height + 'px'
- } else {
- return props.height
- }
- })
- watch(
- () => props.visible,
- (to) => {
- if (to) { // 重置全屏显示
- fullScreen.value = false
- }
- }
- )
- const emits = defineEmits(['close', 'cancel', 'ok'])
- function onBlur () {
- if (!props.loading) {
- emits('close')
- }
- }
- function onFullScreen () {
- fullScreen.value = !fullScreen.value
- }
- function onClose () {
- emits('close')
- }
- function onCancel () {
- emits('cancel')
- }
- function onConfirm () {
- emits('ok')
- }
- </script>
- <template>
- <div class="m-dialog-root">
- <Transition name="mask">
- <div v-show="visible" class="m-dialog-mask"></div>
- </Transition>
- <Transition>
- <div v-show="visible" class="m-dialog-wrap" @click.self="onBlur">
- <div
- ref="dialog"
- :class="['m-dialog', center ? 'relative-hv-center' : 'top-center']"
- :style="`width: ${fullScreen ? '100%' : props.width + 'px'}; top: ${center ? '50%' : (fullScreen ? 0 : top + 'px')};`">
- <div
- class="m-dialog-content"
- :class="{loading: loading}"
- :style="`--height: ${fullScreen ? '100vh' : dialogHeight}`">
- <Spin class="u-spin" :spinning="loading" size="small" />
- <div class="m-dialog-header">
- <p class="u-head">
- <slot name="title">{{ title }}</slot>
- </p>
- </div>
- <span class="m-screen" @click="onFullScreen" v-if="switchFullscreen">
- <svg v-show="!fullScreen" class="u-svg" viewBox="64 64 896 896" data-icon="fullscreen" aria-hidden="true" focusable="false"><path d="M290 236.4l43.9-43.9a8.01 8.01 0 0 0-4.7-13.6L169 160c-5.1-.6-9.5 3.7-8.9 8.9L179 329.1c.8 6.6 8.9 9.4 13.6 4.7l43.7-43.7L370 423.7c3.1 3.1 8.2 3.1 11.3 0l42.4-42.3c3.1-3.1 3.1-8.2 0-11.3L290 236.4zm352.7 187.3c3.1 3.1 8.2 3.1 11.3 0l133.7-133.6 43.7 43.7a8.01 8.01 0 0 0 13.6-4.7L863.9 169c.6-5.1-3.7-9.5-8.9-8.9L694.8 179c-6.6.8-9.4 8.9-4.7 13.6l43.9 43.9L600.3 370a8.03 8.03 0 0 0 0 11.3l42.4 42.4zM845 694.9c-.8-6.6-8.9-9.4-13.6-4.7l-43.7 43.7L654 600.3a8.03 8.03 0 0 0-11.3 0l-42.4 42.3a8.03 8.03 0 0 0 0 11.3L734 787.6l-43.9 43.9a8.01 8.01 0 0 0 4.7 13.6L855 864c5.1.6 9.5-3.7 8.9-8.9L845 694.9zm-463.7-94.6a8.03 8.03 0 0 0-11.3 0L236.3 733.9l-43.7-43.7a8.01 8.01 0 0 0-13.6 4.7L160.1 855c-.6 5.1 3.7 9.5 8.9 8.9L329.2 845c6.6-.8 9.4-8.9 4.7-13.6L290 787.6 423.7 654c3.1-3.1 3.1-8.2 0-11.3l-42.4-42.4z"></path></svg>
- <svg v-show="fullScreen" class="u-svg" viewBox="64 64 896 896" data-icon="fullscreen-exit" aria-hidden="true" focusable="false"><path d="M391 240.9c-.8-6.6-8.9-9.4-13.6-4.7l-43.7 43.7L200 146.3a8.03 8.03 0 0 0-11.3 0l-42.4 42.3a8.03 8.03 0 0 0 0 11.3L280 333.6l-43.9 43.9a8.01 8.01 0 0 0 4.7 13.6L401 410c5.1.6 9.5-3.7 8.9-8.9L391 240.9zm10.1 373.2L240.8 633c-6.6.8-9.4 8.9-4.7 13.6l43.9 43.9L146.3 824a8.03 8.03 0 0 0 0 11.3l42.4 42.3c3.1 3.1 8.2 3.1 11.3 0L333.7 744l43.7 43.7A8.01 8.01 0 0 0 391 783l18.9-160.1c.6-5.1-3.7-9.4-8.8-8.8zm221.8-204.2L783.2 391c6.6-.8 9.4-8.9 4.7-13.6L744 333.6 877.7 200c3.1-3.1 3.1-8.2 0-11.3l-42.4-42.3a8.03 8.03 0 0 0-11.3 0L690.3 279.9l-43.7-43.7a8.01 8.01 0 0 0-13.6 4.7L614.1 401c-.6 5.2 3.7 9.5 8.8 8.9zM744 690.4l43.9-43.9a8.01 8.01 0 0 0-4.7-13.6L623 614c-5.1-.6-9.5 3.7-8.9 8.9L633 783.1c.8 6.6 8.9 9.4 13.6 4.7l43.7-43.7L824 877.7c3.1 3.1 8.2 3.1 11.3 0l42.4-42.3c3.1-3.1 3.1-8.2 0-11.3L744 690.4z"></path></svg>
- </span>
- <span class="m-close" @click="onClose">
- <svg class="u-svg" viewBox="64 64 896 896" data-icon="close" aria-hidden="true" focusable="false"><path d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 0 0 203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"></path></svg>
- </span>
- <div class="m-dialog-body" :style="bodyStyle">
- <slot>{{ content }}</slot>
- </div>
- <div class="m-dialog-footer" v-show="footer">
- <Button class="mr8" @click="onCancel">{{ cancelText }}</Button>
- <Button type="primary" @click="onConfirm">{{ okText }}</Button>
- </div>
- </div>
- </div>
- </div>
- </Transition>
- </div>
- </template>
- <style lang="less" scoped>
- .mask-enter-active, .mask-leave-active {
- transition: opacity .25s;
- }
- .mask-enter-from, .mask-leave-to {
- opacity: 0;
- }
- .v-enter-active, .v-leave-active {
- transition: all .25s;
- }
- .v-enter-from, .v-leave-to {
- opacity: 0;
- transform: scale(0);
- }
- .flex-hv-center { // 水平垂直居中方法①:弹性布局,随内容增大高度,并自适应水平垂直居中
- display: flex;
- justify-content: center;
- align-items: center;
- }
- .relative-hv-center { // 水平垂直居中方法②:相对定位,随内容增大高度,并自适应水平垂直居中
- position: relative;
- top: 50%;
- transform: translateY(-50%);
- }
- .top-center { // 相对定位,固定高度,始终距离视图顶端100px
- position: relative;
- // top: 100px;
- }
- .m-dialog-mask {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 1000;
- background: rgba(0, 0, 0, .45);
- }
- .m-dialog-wrap {
- position: fixed;
- top: 0;
- inset-inline-end: 0;
- bottom: 0;
- inset-inline-start: 0;
- overflow: auto;
- outline: 0;
- inset: 0;
- z-index: 1010;
- .m-dialog {
- margin: 0 auto;
- transition: all .25s;
- .loading { // 加载过程背景虚化
- background: rgb(248, 248, 248) !important;
- pointer-events: none; // 屏蔽鼠标事件
- }
- .m-dialog-content {
- display: flex;
- flex-direction: column;
- height: var(--height);
- position: relative;
- background-color: #fff;
- border-radius: 8px;
- box-shadow: 0 6px 16px 0 rgba(0, 0, 0, .08), 0 3px 6px -4px rgba(0, 0, 0, .12), 0 9px 28px 8px rgba(0, 0, 0, .05);
- padding: 20px 24px;
- transition: all .25s;
- .u-spin {
- position: absolute;
- inset: 0;
- margin: auto;
- }
- .m-dialog-header {
- color: rgba(0, 0, 0, .88);
- background: transparent;
- border-radius: 8px 8px 0 0;
- margin-bottom: 8px;
- max-width: calc(100% - 54px);
- .u-head {
- margin: 0;
- color: rgba(0, 0, 0, .88);
- font-weight: 600;
- font-size: 16px;
- line-height: 1.5;
- word-break: break-all;
- }
- }
- .m-screen {
- .m-close();
- inset-inline-end: 48px;
- }
- .m-close {
- position: absolute;
- top: 17px;
- inset-inline-end: 17px;
- z-index: 1010;
- font-weight: 600;
- line-height: 1;
- background: transparent;
- border-radius: 4px;
- width: 22px;
- height: 22px;
- cursor: pointer;
- transition: background .2s;
- display: flex;
- align-items: center;
- justify-content: center;
- .u-svg {
- display: inline-block;
- width: 16px;
- height: 16px;
- line-height: 22px;
- fill: rgba(0, 0, 0, .45);
- cursor: pointer;
- transition: fill .2s;
- }
- &:hover {
- background: rgba(0, 0, 0, .06);
- .u-svg {
- fill: rgba(0, 0, 0, .88);
- }
- }
- }
- .m-dialog-body {
- flex: 1;
- font-size: 14px;
- color: rgba(0, 0, 0, .88);
- line-height: 1.5714285714285714;
- word-break: break-all;
- overflow: auto;
- transition: all .25s;
- }
- .m-dialog-footer {
- text-align: end;
- background: transparent;
- margin-top: 12px;
- .mr8 {
- margin-inline-end: 8px;
- }
- }
- }
- }
- }
- </style>
②在要使用的页面引入:
- <script setup lang="ts">
- import Dialog from './Dialog.vue'
- import { ref } from 'vue'
-
- const visible1 = ref(false)
- const visible2 = ref(false)
- const visible3 = ref(false)
- const visible4 = ref(false)
- const visible5 = ref(false)
- const visible6 = ref(false)
- const loading = ref(false)
- function showDialog () {
- visible1.value = true
- }
- function showCustomHeightDialog () {
- visible2.value = true
- }
- function showFooterDialog () {
- visible3.value = true
- }
- function showFixPositionDialog () {
- visible4.value = true
- }
- function showFullScreenDialog () {
- visible5.value = true
- }
- function showCustomHBodyDialog () {
- visible6.value = true
- }
- function onClose () { // 关闭回调
- visible1.value = false
- visible2.value = false
- visible3.value = false
- visible4.value = false
- visible5.value = false
- visible6.value = false
- }
- function onCancel () { // “取消”按钮回调
- visible3.value = false
- }
- function onConfirm () { // “确定”,“知道了”按钮回调
- loading.value = true // 开启加载状态
- setTimeout(() => {
- visible3.value = false
- loading.value = false
- }, 500)
- }
- </script>
- <template>
- <div>
- <h1>Dialog 对话框</h1>
- <h2 class="mt30 mb10">基本使用</h2>
- <Space :size="16">
- <Button type="primary" @click="showDialog">默认对话框</Button>
- <Dialog :visible="visible1" @close="onClose">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- <Button type="primary" @click="showCustomHeightDialog">内容高度自定义</Button>
- <Dialog
- :height="360"
- @close="onClose"
- :visible="visible2">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- <Button type="primary" @click="showFooterDialog">有底部按钮</Button>
- <Dialog
- footer
- @close="onClose"
- @cancel="onCancel"
- @ok="onConfirm"
- :loading="loading"
- :visible="visible3">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- <Button type="primary" @click="showFixPositionDialog">位置高度自定义</Button>
- <Dialog
- :center="false"
- :top="120"
- @close="onClose"
- :visible="visible4">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- <Button type="primary" @click="showFullScreenDialog">允许切换全屏</Button>
- <Dialog
- switch-fullscreen
- @close="onClose"
- :visible="visible5">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- <Button type="primary" @click="showCustomHBodyDialog">body 样式自定义</Button>
- <Dialog
- :body-style="{fontSize: '20px', color: '#eb2f96'}"
- @close="onClose"
- :visible="visible6">
- <template #title>Title</template>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- <p>Bla bla ...</p>
- </Dialog>
- </Space>
- </div>
- </template>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。