mirror of
https://github.com/element-plus/element-plus.git
synced 2026-03-13 07:51:17 +08:00
fix(components): [Dialog & MessageBox] support draggable (#5369)
* feat: add use-draggable * feat: msgbox add draggable * feat: update * feat: update * feat: update * feat: update * feat: update * feat: update
This commit is contained in:
@@ -69,6 +69,16 @@ dialog/destroy-on-close
|
||||
|
||||
:::
|
||||
|
||||
## Draggable Dialog
|
||||
|
||||
Try to drag the `header` part.
|
||||
|
||||
:::demo Set `draggable` to `true` to drag.
|
||||
|
||||
dialog/draggable-dialog
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
When using `modal` = false, please make sure that `append-to-body` was set to **true**, because `Dialog` was positioned by `position: relative`, when `modal` gets removed, `Dialog` will position itself based on the current position in the DOM, instead of `Document.Body`, thus the style will be messed up.
|
||||
@@ -94,6 +104,7 @@ When using `modal` = false, please make sure that `append-to-body` was set to **
|
||||
| close-on-press-escape | whether the Dialog can be closed by pressing ESC | boolean | — | true |
|
||||
| show-close | whether to show a close button | boolean | — | true |
|
||||
| before-close | callback before Dialog closes, and it will prevent Dialog from closing | function(done),done is used to close the Dialog | — | — |
|
||||
| draggable | enable dragging feature for Dialog | boolean | — | false |
|
||||
| center | whether to align the header and footer in center | boolean | — | false |
|
||||
| destroy-on-close | Destroy elements in Dialog when closed | boolean | — | false |
|
||||
|
||||
|
||||
@@ -89,12 +89,22 @@ message-box/distinguishable-close-cancel
|
||||
|
||||
Content of MessageBox can be centered.
|
||||
|
||||
:::demo Setting `center` to `true` will center the content
|
||||
:::demo Setting `center` to `true` will center the content.
|
||||
|
||||
message-box/centered-content
|
||||
|
||||
:::
|
||||
|
||||
## Draggable
|
||||
|
||||
MessageBox can be draggable.
|
||||
|
||||
:::demo Setting `draggable` to `true` allows user to drag MessageBox.
|
||||
|
||||
message-box/draggable
|
||||
|
||||
:::
|
||||
|
||||
## Global method
|
||||
|
||||
If Element Plus is fully imported, it will add the following global methods for `app.config.globalProperties`: `$msgbox`, `$alert`, `$confirm` and `$prompt`. So in a Vue instance you can call `MessageBox` like what we did in this page. The parameters are:
|
||||
@@ -147,5 +157,6 @@ The corresponding methods are: `ElMessageBox`, `ElMessageBox.alert`, `ElMessageB
|
||||
| input-validator | validation function for the input. Should returns a boolean or string. If a string is returned, it will be assigned to inputErrorMessage | function | — | — |
|
||||
| input-error-message | error message when validation fails | string | — | Illegal input |
|
||||
| center | whether to align the content in center | boolean | — | false |
|
||||
| draggable | whether MessageBox is draggable | boolean | — | false |
|
||||
| round-button | whether to use round button | boolean | — | false |
|
||||
| button-size | custom size of confirm and cancel buttons | string | small / default / large | default |
|
||||
|
||||
23
docs/examples/dialog/draggable-dialog.vue
Normal file
23
docs/examples/dialog/draggable-dialog.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<el-button type="text" @click="dialogVisible = true"
|
||||
>Click to open Dialog
|
||||
</el-button>
|
||||
|
||||
<el-dialog v-model="dialogVisible" title="Tips" width="30%" draggable>
|
||||
<span>It's a draggable Dialog</span>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="dialogVisible = false"
|
||||
>Confirm</el-button
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue'
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
</script>
|
||||
32
docs/examples/message-box/draggable.vue
Normal file
32
docs/examples/message-box/draggable.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<el-button type="text" @click="open">Click to open Message Box</el-button>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
|
||||
const open = () => {
|
||||
ElMessageBox.confirm(
|
||||
'proxy will permanently delete the file. Continue?',
|
||||
'Warning',
|
||||
{
|
||||
confirmButtonText: 'OK',
|
||||
cancelButtonText: 'Cancel',
|
||||
type: 'warning',
|
||||
draggable: true,
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: 'Delete completed',
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
ElMessage({
|
||||
type: 'info',
|
||||
message: 'Delete canceled',
|
||||
})
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -275,5 +275,22 @@ describe('Dialog.vue', () => {
|
||||
const svg = mount(Delete).find('svg').element
|
||||
expect(closeIcon.element.innerHTML).toBe(svg.innerHTML)
|
||||
})
|
||||
|
||||
test('should render draggable prop', async () => {
|
||||
const wrapper = _mount({
|
||||
slots: {
|
||||
default: AXIOM,
|
||||
},
|
||||
props: {
|
||||
modelValue: true,
|
||||
draggable: true,
|
||||
},
|
||||
})
|
||||
|
||||
await nextTick()
|
||||
await rAF()
|
||||
await nextTick()
|
||||
expect(wrapper.find('.is-draggable').exists()).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -39,6 +39,10 @@ export const dialogProps = buildProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
lockScroll: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
'el-dialog',
|
||||
{
|
||||
'is-fullscreen': fullscreen,
|
||||
'is-draggable': draggable,
|
||||
'el-dialog--center': center,
|
||||
},
|
||||
customClass,
|
||||
@@ -36,7 +37,7 @@
|
||||
:style="style"
|
||||
@click.stop=""
|
||||
>
|
||||
<div class="el-dialog__header">
|
||||
<div ref="headerRef" class="el-dialog__header">
|
||||
<slot name="title">
|
||||
<span class="el-dialog__title">
|
||||
{{ title }}
|
||||
@@ -70,12 +71,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue'
|
||||
import { computed, defineComponent, ref } from 'vue'
|
||||
import { TrapFocus } from '@element-plus/directives'
|
||||
import { ElOverlay } from '@element-plus/components/overlay'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { CloseComponents } from '@element-plus/utils/icon'
|
||||
import { useSameTarget } from '@element-plus/hooks'
|
||||
import { useDraggable, useSameTarget } from '@element-plus/hooks'
|
||||
import { dialogProps, dialogEmits } from './dialog'
|
||||
import { useDialog } from './use-dialog'
|
||||
|
||||
@@ -95,11 +96,16 @@ export default defineComponent({
|
||||
|
||||
setup(props, ctx) {
|
||||
const dialogRef = ref<HTMLElement>()
|
||||
const headerRef = ref<HTMLElement>()
|
||||
const dialog = useDialog(props, ctx, dialogRef)
|
||||
const overlayEvent = useSameTarget(dialog.onModalClick)
|
||||
|
||||
const draggable = computed(() => props.draggable && !props.fullscreen)
|
||||
useDraggable(dialogRef, headerRef, draggable)
|
||||
|
||||
return {
|
||||
dialogRef,
|
||||
headerRef,
|
||||
overlayEvent,
|
||||
...dialog,
|
||||
}
|
||||
|
||||
@@ -5,112 +5,122 @@
|
||||
:z-index="zIndex"
|
||||
:overlay-class="['is-message-box', modalClass]"
|
||||
:mask="modal"
|
||||
@click.self="handleWrapperClick"
|
||||
>
|
||||
<div
|
||||
ref="root"
|
||||
v-trap-focus
|
||||
role="dialog"
|
||||
:aria-label="title || 'dialog'"
|
||||
aria-modal="true"
|
||||
:class="[
|
||||
'el-message-box',
|
||||
customClass,
|
||||
{ 'el-message-box--center': center },
|
||||
]"
|
||||
:style="customStyle"
|
||||
class="el-overlay-message-box"
|
||||
@click="overlayEvent.onClick"
|
||||
@mousedown="overlayEvent.onMousedown"
|
||||
@mouseup="overlayEvent.onMouseup"
|
||||
>
|
||||
<div
|
||||
v-if="title !== null && title !== undefined"
|
||||
class="el-message-box__header"
|
||||
ref="rootRef"
|
||||
v-trap-focus
|
||||
role="dialog"
|
||||
:aria-label="title || 'dialog'"
|
||||
aria-modal="true"
|
||||
:class="[
|
||||
'el-message-box',
|
||||
customClass,
|
||||
{ 'el-message-box--center': center, 'is-draggable': draggable },
|
||||
]"
|
||||
:style="customStyle"
|
||||
@click.stop=""
|
||||
>
|
||||
<div class="el-message-box__title">
|
||||
<el-icon
|
||||
v-if="iconComponent && center"
|
||||
class="el-message-box__status"
|
||||
:class="typeClass"
|
||||
>
|
||||
<component :is="iconComponent" />
|
||||
</el-icon>
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
<button
|
||||
v-if="showClose"
|
||||
type="button"
|
||||
class="el-message-box__headerbtn"
|
||||
aria-label="Close"
|
||||
@click="
|
||||
handleAction(distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
"
|
||||
@keydown.prevent.enter="
|
||||
handleAction(distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
"
|
||||
<div
|
||||
v-if="title !== null && title !== undefined"
|
||||
ref="headerRef"
|
||||
class="el-message-box__header"
|
||||
>
|
||||
<el-icon class="el-message-box__close"><close /></el-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="el-message-box__content">
|
||||
<div class="el-message-box__container">
|
||||
<el-icon
|
||||
v-if="iconComponent && !center && hasMessage"
|
||||
class="el-message-box__status"
|
||||
:class="typeClass"
|
||||
<div class="el-message-box__title">
|
||||
<el-icon
|
||||
v-if="iconComponent && center"
|
||||
class="el-message-box__status"
|
||||
:class="typeClass"
|
||||
>
|
||||
<component :is="iconComponent" />
|
||||
</el-icon>
|
||||
<span>{{ title }}</span>
|
||||
</div>
|
||||
<button
|
||||
v-if="showClose"
|
||||
type="button"
|
||||
class="el-message-box__headerbtn"
|
||||
aria-label="Close"
|
||||
@click="
|
||||
handleAction(distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
"
|
||||
@keydown.prevent.enter="
|
||||
handleAction(distinguishCancelAndClose ? 'close' : 'cancel')
|
||||
"
|
||||
>
|
||||
<component :is="iconComponent" />
|
||||
</el-icon>
|
||||
<div v-if="hasMessage" class="el-message-box__message">
|
||||
<slot>
|
||||
<p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
|
||||
<p v-else v-html="message"></p>
|
||||
</slot>
|
||||
<el-icon class="el-message-box__close">
|
||||
<close />
|
||||
</el-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="el-message-box__content">
|
||||
<div class="el-message-box__container">
|
||||
<el-icon
|
||||
v-if="iconComponent && !center && hasMessage"
|
||||
class="el-message-box__status"
|
||||
:class="typeClass"
|
||||
>
|
||||
<component :is="iconComponent" />
|
||||
</el-icon>
|
||||
<div v-if="hasMessage" class="el-message-box__message">
|
||||
<slot>
|
||||
<p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
|
||||
<p v-else v-html="message"></p>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showInput" class="el-message-box__input">
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-model="inputValue"
|
||||
:type="inputType"
|
||||
:placeholder="inputPlaceholder"
|
||||
:class="{ invalid: validateError }"
|
||||
@keydown.prevent.enter="handleInputEnter"
|
||||
/>
|
||||
<div
|
||||
class="el-message-box__errormsg"
|
||||
:style="{
|
||||
visibility: !!editorErrorMessage ? 'visible' : 'hidden',
|
||||
}"
|
||||
>
|
||||
{{ editorErrorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showInput" class="el-message-box__input">
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-model="inputValue"
|
||||
:type="inputType"
|
||||
:placeholder="inputPlaceholder"
|
||||
:class="{ invalid: validateError }"
|
||||
@keydown.prevent.enter="handleInputEnter"
|
||||
/>
|
||||
<div
|
||||
class="el-message-box__errormsg"
|
||||
:style="{
|
||||
visibility: !!editorErrorMessage ? 'visible' : 'hidden',
|
||||
}"
|
||||
<div class="el-message-box__btns">
|
||||
<el-button
|
||||
v-if="showCancelButton"
|
||||
:loading="cancelButtonLoading"
|
||||
:class="[cancelButtonClass]"
|
||||
:round="roundButton"
|
||||
:size="btnSize"
|
||||
@click="handleAction('cancel')"
|
||||
@keydown.prevent.enter="handleAction('cancel')"
|
||||
>
|
||||
{{ editorErrorMessage }}
|
||||
</div>
|
||||
{{ cancelButtonText || t('el.messagebox.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-show="showConfirmButton"
|
||||
ref="confirmRef"
|
||||
type="primary"
|
||||
:loading="confirmButtonLoading"
|
||||
:class="[confirmButtonClasses]"
|
||||
:round="roundButton"
|
||||
:disabled="confirmButtonDisabled"
|
||||
:size="btnSize"
|
||||
@click="handleAction('confirm')"
|
||||
@keydown.prevent.enter="handleAction('confirm')"
|
||||
>
|
||||
{{ confirmButtonText || t('el.messagebox.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-message-box__btns">
|
||||
<el-button
|
||||
v-if="showCancelButton"
|
||||
:loading="cancelButtonLoading"
|
||||
:class="[cancelButtonClass]"
|
||||
:round="roundButton"
|
||||
:size="btnSize"
|
||||
@click="handleAction('cancel')"
|
||||
@keydown.prevent.enter="handleAction('cancel')"
|
||||
>
|
||||
{{ cancelButtonText || t('el.messagebox.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
v-show="showConfirmButton"
|
||||
ref="confirmRef"
|
||||
type="primary"
|
||||
:loading="confirmButtonLoading"
|
||||
:class="[confirmButtonClasses]"
|
||||
:round="roundButton"
|
||||
:disabled="confirmButtonDisabled"
|
||||
:size="btnSize"
|
||||
@click="handleAction('confirm')"
|
||||
@keydown.prevent.enter="handleAction('confirm')"
|
||||
>
|
||||
{{ confirmButtonText || t('el.messagebox.confirm') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-overlay>
|
||||
</transition>
|
||||
@@ -136,6 +146,8 @@ import {
|
||||
useRestoreActive,
|
||||
usePreventGlobal,
|
||||
useSize,
|
||||
useDraggable,
|
||||
useSameTarget,
|
||||
} from '@element-plus/hooks'
|
||||
import ElInput from '@element-plus/components/input'
|
||||
import { ElOverlay } from '@element-plus/components/overlay'
|
||||
@@ -146,7 +158,7 @@ import { isValidComponentSize } from '@element-plus/utils/validators'
|
||||
import { ElIcon } from '@element-plus/components/icon'
|
||||
import { TypeComponents, TypeComponentsMap } from '@element-plus/utils/icon'
|
||||
|
||||
import type { ComponentPublicInstance, PropType } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import type { ComponentSize } from '@element-plus/utils/types'
|
||||
import type {
|
||||
Action,
|
||||
@@ -197,6 +209,7 @@ export default defineComponent({
|
||||
default: true,
|
||||
},
|
||||
center: Boolean,
|
||||
draggable: Boolean,
|
||||
roundButton: {
|
||||
default: false,
|
||||
type: Boolean,
|
||||
@@ -270,8 +283,10 @@ export default defineComponent({
|
||||
() => state.icon || TypeComponentsMap[state.type] || ''
|
||||
)
|
||||
const hasMessage = computed(() => !!state.message)
|
||||
const inputRef = ref<ComponentPublicInstance>(null)
|
||||
const confirmRef = ref<ComponentPublicInstance>(null)
|
||||
const rootRef = ref<HTMLElement>()
|
||||
const headerRef = ref<HTMLElement>()
|
||||
const inputRef = ref<HTMLElement>()
|
||||
const confirmRef = ref<HTMLElement>()
|
||||
|
||||
const confirmButtonClasses = computed(() => state.confirmButtonClass)
|
||||
|
||||
@@ -311,6 +326,9 @@ export default defineComponent({
|
||||
}
|
||||
)
|
||||
|
||||
const draggable = computed(() => props.draggable)
|
||||
useDraggable(rootRef, headerRef, draggable)
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
if (props.closeOnHashChange) {
|
||||
@@ -338,6 +356,8 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
const overlayEvent = useSameTarget(handleWrapperClick)
|
||||
|
||||
const handleInputEnter = () => {
|
||||
if (state.inputType !== 'textarea') {
|
||||
return handleAction('confirm')
|
||||
@@ -428,12 +448,15 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
overlayEvent,
|
||||
visible,
|
||||
hasMessage,
|
||||
typeClass,
|
||||
btnSize,
|
||||
iconComponent,
|
||||
confirmButtonClasses,
|
||||
rootRef,
|
||||
headerRef,
|
||||
inputRef,
|
||||
confirmRef,
|
||||
doClose, // for outside usage
|
||||
|
||||
@@ -92,6 +92,9 @@ export interface ElMessageBoxOptions {
|
||||
/** Whether to align the content in center */
|
||||
center?: boolean
|
||||
|
||||
/** Whether MessageBox can be drag */
|
||||
draggable?: boolean
|
||||
|
||||
/** Content of the MessageBox */
|
||||
message?: string | VNode
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './use-attrs'
|
||||
export * from './use-common-props'
|
||||
export * from './use-draggable'
|
||||
export * from './use-focus'
|
||||
export * from './use-form-item'
|
||||
export * from './use-global-config'
|
||||
|
||||
87
packages/hooks/use-draggable/index.ts
Normal file
87
packages/hooks/use-draggable/index.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
import { onBeforeUnmount, onMounted, watchEffect } from 'vue'
|
||||
import { addUnit } from '@element-plus/utils/util'
|
||||
import type { Ref, ComputedRef } from 'vue'
|
||||
|
||||
export const useDraggable = (
|
||||
targetRef: Ref<HTMLElement | undefined>,
|
||||
dragRef: Ref<HTMLElement | undefined>,
|
||||
draggable: ComputedRef<boolean>
|
||||
) => {
|
||||
let transform = {
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
}
|
||||
|
||||
const onMousedown = (e: MouseEvent) => {
|
||||
const downX = e.clientX
|
||||
const downY = e.clientY
|
||||
const { offsetX, offsetY } = transform
|
||||
|
||||
const targetRect = targetRef.value.getBoundingClientRect()
|
||||
const targetLeft = targetRect.left
|
||||
const targetTop = targetRect.top
|
||||
const targetWidth = targetRect.width
|
||||
const targetHeight = targetRect.height
|
||||
|
||||
const clientWidth = document.documentElement.clientWidth
|
||||
const clientHeight = document.documentElement.clientHeight
|
||||
|
||||
const minLeft = -targetLeft + offsetX
|
||||
const minTop = -targetTop + offsetY
|
||||
const maxLeft = clientWidth - targetLeft - targetWidth + offsetX
|
||||
const maxTop = clientHeight - targetTop - targetHeight + offsetY
|
||||
|
||||
const onMousemove = (e: MouseEvent) => {
|
||||
const moveX = Math.min(
|
||||
Math.max(offsetX + e.clientX - downX, minLeft),
|
||||
maxLeft
|
||||
)
|
||||
const moveY = Math.min(
|
||||
Math.max(offsetY + e.clientY - downY, minTop),
|
||||
maxTop
|
||||
)
|
||||
|
||||
transform = {
|
||||
offsetX: moveX,
|
||||
offsetY: moveY,
|
||||
}
|
||||
targetRef.value.style.transform = `translate(${addUnit(moveX)}, ${addUnit(
|
||||
moveY
|
||||
)})`
|
||||
}
|
||||
|
||||
const onMouseup = () => {
|
||||
document.removeEventListener('mousemove', onMousemove)
|
||||
document.removeEventListener('mouseup', onMouseup)
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', onMousemove)
|
||||
document.addEventListener('mouseup', onMouseup)
|
||||
}
|
||||
|
||||
const onDraggable = () => {
|
||||
if (dragRef.value && targetRef.value) {
|
||||
dragRef.value.addEventListener('mousedown', onMousedown)
|
||||
}
|
||||
}
|
||||
|
||||
const offDraggable = () => {
|
||||
if (dragRef.value && targetRef.value) {
|
||||
dragRef.value.removeEventListener('mousedown', onMousedown)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
watchEffect(() => {
|
||||
if (draggable.value) {
|
||||
onDraggable()
|
||||
} else {
|
||||
offDraggable()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
offDraggable()
|
||||
})
|
||||
}
|
||||
@@ -35,6 +35,13 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@include when(draggable) {
|
||||
@include e(header) {
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include e(header) {
|
||||
padding: var(--el-dialog-padding-primary);
|
||||
padding-bottom: 10px;
|
||||
|
||||
@@ -24,13 +24,29 @@
|
||||
backface-visibility: hidden;
|
||||
|
||||
@at-root .#{$namespace}-overlay.is-message-box {
|
||||
text-align: center;
|
||||
&::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
vertical-align: middle;
|
||||
.#{$namespace}-overlay-message-box {
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include when(draggable) {
|
||||
@include e(header) {
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +103,7 @@
|
||||
|
||||
& div.invalid > input {
|
||||
border-color: var(--el-color-error);
|
||||
|
||||
&:focus {
|
||||
border-color: var(--el-color-error);
|
||||
}
|
||||
@@ -152,12 +169,6 @@
|
||||
|
||||
// centerAlign 布局
|
||||
@include m(center) {
|
||||
padding-bottom: 30px;
|
||||
|
||||
@include e(header) {
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
@include e(title) {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -191,13 +202,13 @@
|
||||
}
|
||||
|
||||
.fade-in-linear-enter-active {
|
||||
.#{$namespace}-message-box {
|
||||
.#{$namespace}-overlay-message-box {
|
||||
animation: msgbox-fade-in var(--el-transition-duration);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in-linear-leave-active {
|
||||
.#{$namespace}-message-box {
|
||||
.#{$namespace}-overlay-message-box {
|
||||
animation: msgbox-fade-in var(--el-transition-duration) reverse;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user