Skip to content

Commit

Permalink
Merge pull request #963 from huoyuhao/feat/dialog/position
Browse files Browse the repository at this point in the history
  • Loading branch information
honkinglin authored Jun 10, 2022
2 parents cabcff5 + bc9ce85 commit 4b144cc
Show file tree
Hide file tree
Showing 7 changed files with 2,904 additions and 2,098 deletions.
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

0 comments on commit 4b144cc

Please sign in to comment.