push
This commit is contained in:
12
lib/component/modal/index.ts
Normal file
12
lib/component/modal/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
import { Modal as AntModel } from 'ant-design-vue';
|
||||
|
||||
import modal from './modal.vue';
|
||||
import { withInstall } from '/nerv-lib/util';
|
||||
import './model.less';
|
||||
|
||||
Object.keys(AntModel).forEach((key) => {
|
||||
!modal[key] && (modal[key] = AntModel[key]);
|
||||
});
|
||||
|
||||
export const NsModal = withInstall(modal);
|
||||
44
lib/component/modal/modal.vue
Normal file
44
lib/component/modal/modal.vue
Normal file
@@ -0,0 +1,44 @@
|
||||
<!-- @format -->
|
||||
|
||||
<template>
|
||||
<a-modal v-bind="getBindValue">
|
||||
<template #[item]="data" v-for="item in Object.keys($slots)" :key="item">
|
||||
<slot :name="item" v-bind="data || {}"></slot>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, toRefs } from 'vue';
|
||||
import { useModalDrag } from '/nerv-lib/component/modal/useModalDrag';
|
||||
import { modalProps } from 'ant-design-vue/es/modal/Modal';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NsModal',
|
||||
props: {
|
||||
...modalProps(),
|
||||
draggable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
searchData: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
setup(props, { attrs, emit }) {
|
||||
const { visible, draggable, destroyOnClose } = toRefs(props);
|
||||
useModalDrag({
|
||||
visible,
|
||||
destroyOnClose,
|
||||
draggable,
|
||||
});
|
||||
const getBindValue = computed(() => ({
|
||||
...attrs,
|
||||
...props,
|
||||
}));
|
||||
return { getBindValue };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
||||
6
lib/component/modal/model.less
Normal file
6
lib/component/modal/model.less
Normal file
@@ -0,0 +1,6 @@
|
||||
.ant-modal {
|
||||
padding-bottom: 0;
|
||||
.ant-modal-header{
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
113
lib/component/modal/useModalDrag.ts
Normal file
113
lib/component/modal/useModalDrag.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
import { Ref, unref } from 'vue';
|
||||
import { watchDebounced } from '@vueuse/core';
|
||||
|
||||
interface ModalDragContext {
|
||||
draggable: Ref<boolean>;
|
||||
destroyOnClose: Ref<boolean | undefined> | undefined;
|
||||
visible: Ref<boolean | undefined>;
|
||||
}
|
||||
|
||||
export function useModalDrag(context: ModalDragContext) {
|
||||
const getStyle = (dom: any, attr: any) => {
|
||||
return getComputedStyle(dom)[attr];
|
||||
};
|
||||
const drag = (wrap: any) => {
|
||||
if (!wrap) return;
|
||||
wrap.setAttribute('data-drag', unref(context.draggable));
|
||||
const dialogHeaderEl = wrap.querySelector('.ant-modal-header');
|
||||
const dragDom = wrap.querySelector('.ant-modal');
|
||||
|
||||
if (!dialogHeaderEl || !dragDom || !unref(context.draggable)) return;
|
||||
|
||||
dialogHeaderEl.style.cursor = 'move';
|
||||
|
||||
dialogHeaderEl.onmousedown = (e: any) => {
|
||||
if (!e) return;
|
||||
// 鼠标按下,计算当前元素距离可视区的距离
|
||||
const disX = e.clientX;
|
||||
const disY = e.clientY;
|
||||
const screenWidth = document.body.clientWidth; // body当前宽度
|
||||
const screenHeight = document.documentElement.clientHeight; // 可见区域高度(应为body高度,可某些环境下无法获取)
|
||||
|
||||
const dragDomWidth = dragDom.offsetWidth; // 对话框宽度
|
||||
const dragDomheight = dragDom.offsetHeight; // 对话框高度
|
||||
|
||||
const minDragDomLeft = dragDom.offsetLeft;
|
||||
|
||||
const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth;
|
||||
const minDragDomTop = dragDom.offsetTop;
|
||||
const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomheight;
|
||||
// 获取到的值带px 正则匹配替换
|
||||
const domLeft = getStyle(dragDom, 'left');
|
||||
const domTop = getStyle(dragDom, 'top');
|
||||
let styL = +domLeft;
|
||||
let styT = +domTop;
|
||||
|
||||
// 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
|
||||
if (domLeft.includes('%')) {
|
||||
styL = +document.body.clientWidth * (+domLeft.replace(/%/g, '') / 100);
|
||||
styT = +document.body.clientHeight * (+domTop.replace(/%/g, '') / 100);
|
||||
} else {
|
||||
styL = +domLeft.replace(/px/g, '');
|
||||
styT = +domTop.replace(/px/g, '');
|
||||
}
|
||||
|
||||
document.onmousemove = function (e) {
|
||||
// 通过事件委托,计算移动的距离
|
||||
let left = e.clientX - disX;
|
||||
let top = e.clientY - disY;
|
||||
|
||||
// 边界处理
|
||||
if (-left > minDragDomLeft) {
|
||||
left = -minDragDomLeft;
|
||||
} else if (left > maxDragDomLeft) {
|
||||
left = maxDragDomLeft;
|
||||
}
|
||||
|
||||
if (-top > minDragDomTop) {
|
||||
top = -minDragDomTop;
|
||||
} else if (top > maxDragDomTop) {
|
||||
top = maxDragDomTop;
|
||||
}
|
||||
|
||||
// 移动当前元素
|
||||
dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;`;
|
||||
};
|
||||
|
||||
document.onmouseup = () => {
|
||||
document.onmousemove = null;
|
||||
document.onmouseup = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
const handleDrag = () => {
|
||||
const dragWraps = document.querySelectorAll('.ant-modal-wrap');
|
||||
for (const wrap of Array.from(dragWraps)) {
|
||||
if (!wrap) continue;
|
||||
const display = getStyle(wrap, 'display');
|
||||
const draggable = wrap.getAttribute('data-drag');
|
||||
console.log('display', display);
|
||||
if (display !== 'none') {
|
||||
// 拖拽位置
|
||||
if (draggable === null || unref(context.destroyOnClose)) {
|
||||
drag(wrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
watchDebounced(
|
||||
[() => context.draggable.value, () => context.visible.value],
|
||||
() => {
|
||||
if (!unref(context.visible) || !unref(context.draggable)) {
|
||||
return;
|
||||
}
|
||||
handleDrag();
|
||||
},
|
||||
|
||||
{
|
||||
debounce: 30,
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user