Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1、问题/原因: #963

Merged
merged 2 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions examples/dialog/demos/modal.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
<template>
<div>
<t-button theme="primary" @click="visibleNormalDrag = true">普通对话框 </t-button>
<t-button theme="primary" @click="visibleModal = true"> 模态对话框 </t-button>
<t-button theme="primary" @click="visibleModelessDrag = true"> 非模态对话框 </t-button>

<t-dialog
v-model:visible="visibleNormalDrag"
header="普通对话框"
mode="modal"
draggable
:on-confirm="() => (visibleNormalDrag = false)"
>
<template #body>
<div>我是内容</div>
<div>我是内容</div>
</template>
</t-dialog>
<t-dialog
v-model:visible="visibleModal"
header="模态对话框"
Expand All @@ -27,13 +40,15 @@
<template #body>
<div>我是内容</div>
<div>我是内容</div>
<div>我是内容</div>
</template>
</t-dialog>
</div>
</template>
<script setup>
import { ref } from 'vue';

const visibleNormalDrag = ref(false);
const visibleModal = ref(false);
const visibleModelessDrag = ref(false);
</script>
Expand Down
52 changes: 52 additions & 0 deletions examples/dialog/demos/position.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<t-button theme="primary" @click="visible = true"> 默认位置 </t-button>
<t-button theme="primary" @click="visibleCenter = true"> 垂直居中 </t-button>
<t-button theme="primary" @click="visibleTop = true"> 自定义top </t-button>
<t-button theme="primary" @click="visibleOverflow = true"> 垂直居中元素溢出场景 </t-button>
<t-dialog header="对话框标题" body="对话框内容" :visible="visible" :on-close="close1" :on-confirm="close1" />
<t-dialog
placement="center"
Expand All @@ -21,6 +22,53 @@
:on-confirm="close3"
:on-close="close3"
/>
<t-dialog placement="center" header="对话框标题" :visible="visibleOverflow" :on-confirm="close4" :on-close="close4">
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
<p>水平居中显示的对话框</p>
</t-dialog>
</div>
</template>
<script setup lang="ts">
Expand All @@ -29,6 +77,7 @@ import { ref } from 'vue';
const visible = ref(false);
const visibleCenter = ref(false);
const visibleTop = ref(false);
const visibleOverflow = ref(false);
const placement = 'top';
const top = '50px';

Expand All @@ -41,6 +90,9 @@ const close2 = () => {
const close3 = () => {
visibleTop.value = false;
};
const close4 = () => {
visibleOverflow.value = false;
};
</script>
<style scoped>
.t-button {
Expand Down
2 changes: 1 addition & 1 deletion src/_common
110 changes: 66 additions & 44 deletions src/dialog/dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, ref, Transition, watch } from 'vue';
import isNumber from 'lodash/isNumber';
import { CloseIcon, InfoCircleFilledIcon, CheckCircleFilledIcon, ErrorCircleFilledIcon } from 'tdesign-icons-vue-next';
import TButton from '../button';
import { DialogCloseContext, TdDialogProps } from './type';
Expand Down Expand Up @@ -29,18 +30,29 @@ if (typeof window !== 'undefined' && window.document && window.document.document
document.documentElement.addEventListener('click', getClickPosition, true);
}

// 注册元素的拖拽事件
function InitDragEvent(dragBox: HTMLElement) {
const target = dragBox;
const windowInnerWidth = window.innerWidth || document.documentElement.clientWidth;
const windowInnerHeight = window.innerHeight || document.documentElement.clientHeight;
target.addEventListener('mousedown', (targetEvent: MouseEvent) => {
// 算出鼠标相对元素的位置
const disX = targetEvent.clientX - target.offsetLeft;
const disY = targetEvent.clientY - target.offsetTop;
const dialogW = target.offsetWidth;
const dialogH = target.offsetHeight;
// 如果弹出框超出屏幕范围 不能进行拖拽
if (dialogW > windowInnerWidth || dialogH > windowInnerHeight) return;
function mouseMoverHandler(documentEvent: MouseEvent) {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
const left = documentEvent.clientX - disX;
const top = documentEvent.clientY - disY;
// 移动当前元素
let left = documentEvent.clientX - disX;
let top = documentEvent.clientY - disY;
// 临界判断
// 拖拽上左边界限制
if (left < 0) left = 0;
if (top < 0) top = 0;
if (windowInnerWidth - target.offsetWidth - left < 0) left = windowInnerWidth - target.offsetWidth;
if (windowInnerHeight - target.offsetHeight - top < 0) top = windowInnerHeight - target.offsetHeight;
target.style.position = 'absolute';
target.style.left = `${left}px`;
target.style.top = `${top}px`;
}
Expand Down Expand Up @@ -109,11 +121,26 @@ export default defineComponent({
// 是否模态形式的对话框
const isModal = computed(() => props.mode === 'modal');
// 是否非模态对话框
const isModeless = computed(() => props.mode === 'modeless');
const isModeLess = computed(() => props.mode === 'modeless');
const maskClass = computed(() => [
`${COMPONENT_NAME.value}__mask`,
!props.showOverlay && `${classPrefix.value}-is-hidden`,
]);
const positionClass = computed(() => [
`${COMPONENT_NAME.value}__position`,
!!props.top && `${COMPONENT_NAME.value}--top`,
`${props.placement && !props.top ? `${COMPONENT_NAME.value}--${props.placement}` : ''}`,
]);
const positionStyle = computed(() => {
// 此处获取定位方式 top 优先级较高 存在时 默认使用top定位
const { top } = props;
let topStyle = {};
if (top !== undefined) {
const topValue = GetCSSValue(top);
topStyle = { paddingTop: topValue };
}
return topStyle;
});
const dialogClass = computed(() => {
const dialogClass = [
`${COMPONENT_NAME.value}`,
Expand All @@ -122,31 +149,14 @@ export default defineComponent({
`${COMPONENT_NAME.value}__modal-${props.theme}`,
];
if (['modeless', 'modal'].includes(props.mode)) {
dialogClass.push(`${COMPONENT_NAME.value}--fixed`);
if (isModal.value && props.showInAttachedElement) {
dialogClass.push(`${COMPONENT_NAME.value}--absolute`);
}
}
return dialogClass;
});
const dialogStyle = computed(() => {
const { top, placement } = props;
let topStyle = {};

// 设置了top属性
if (top) {
const topValue = GetCSSValue(top);
topStyle = {
top: topValue,
transform: 'translate(-50%, 0)',
maxHeight: `calc(100% - ${topValue})`,
};
} else if (placement === 'top') {
topStyle = {
maxHeight: 'calc(100% - 20%)',
};
}
return { width: GetCSSValue(props.width), ...topStyle };
return { width: GetCSSValue(props.width) };
});

watch(
Expand All @@ -158,7 +168,7 @@ export default defineComponent({
const bodyCssText = `position: relative;width: calc(100% - ${scrollWidth.value}px);`;
document.body.style.cssText = bodyCssText;
}
!isModeless.value && addClass(document.body, LOCK_CLASS.value);
!isModeLess.value && addClass(document.body, LOCK_CLASS.value);
nextTick(() => {
if (mousePosition && dialogEle.value) {
dialogEle.value.style.transformOrigin = `${mousePosition.x - dialogEle.value.offsetLeft}px ${
Expand Down Expand Up @@ -195,6 +205,8 @@ export default defineComponent({
}
};
const overlayAction = (e: MouseEvent) => {
// 如果不是modal模式 默认没有mask 也就没有相关点击事件
if (props.mode !== 'modal') return;
props.onOverlayClick?.({ e });
// 根据closeOnClickOverlay判断点击蒙层时是否触发close事件
if (props.closeOnOverlayClick) {
Expand All @@ -218,6 +230,12 @@ export default defineComponent({
};
// 关闭弹窗动画结束时事件
const afterLeave = () => {
if (isModeLess.value && props.draggable) {
// 关闭弹窗 清空拖拽设置的相关css
dialogEle.value.style.position = 'relative';
dialogEle.value.style.left = 'unset';
dialogEle.value.style.top = 'unset';
}
props.onClosed?.();
};

Expand Down Expand Up @@ -270,24 +288,29 @@ export default defineComponent({
props.theme === 'default' ? `${COMPONENT_NAME.value}__body` : `${COMPONENT_NAME.value}__body__icon`;
return (
// /* 非模态形态下draggable为true才允许拖拽 */
<div
key="dialog"
class={dialogClass.value}
style={dialogStyle.value}
v-draggable={isModeless.value && props.draggable}
ref="dialogEle"
>
<div class={`${COMPONENT_NAME.value}__header`}>
{getIcon()}
{renderTNodeJSX('header', defaultHeader)}

<div class={`${COMPONENT_NAME.value}__wrap`} onClick={overlayAction}>
<div class={positionClass.value} style={positionStyle.value}>
<div
key="dialog"
class={dialogClass.value}
style={dialogStyle.value}
v-draggable={isModeLess.value && props.draggable}
ref="dialogEle"
>
<div class={`${COMPONENT_NAME.value}__header`}>
{getIcon()}
{renderTNodeJSX('header', defaultHeader)}
</div>
{props.closeBtn ? (
<span class={`${COMPONENT_NAME.value}__close`} onClick={closeBtnAction}>
{renderTNodeJSX('closeBtn', defaultCloseBtn)}
</span>
) : null}
<div class={bodyClassName}>{body}</div>
<div class={`${COMPONENT_NAME.value}__footer`}>{renderTNodeJSX('footer', defaultFooter)}</div>
</div>
</div>
{props.closeBtn ? (
<span class={`${COMPONENT_NAME.value}__close`} onClick={closeBtnAction}>
{renderTNodeJSX('closeBtn', defaultCloseBtn)}
</span>
) : null}
<div class={bodyClassName}>{body}</div>
<div class={`${COMPONENT_NAME.value}__footer`}>{renderTNodeJSX('footer', defaultFooter)}</div>
</div>
);
};
Expand All @@ -303,7 +326,7 @@ export default defineComponent({
COMPONENT_NAME,
scrollWidth,
isModal,
isModeless,
isModeLess,
maskClass,
dialogClass,
dialogStyle,
Expand All @@ -312,12 +335,11 @@ export default defineComponent({
afterLeave,
hasEventOn,
renderDialog,
overlayAction,
};
},
render() {
const { COMPONENT_NAME } = this;
const maskView = this.isModal && <div key="mask" class={this.maskClass} onClick={this.overlayAction}></div>;
const maskView = this.isModal && <div key="mask" class={this.maskClass}></div>;
const dialogView = this.renderDialog();
const view = [maskView, dialogView];
const ctxStyle = { zIndex: this.zIndex };
Expand Down
Loading