mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-13 16:35:56 +08:00
181 lines
4.8 KiB
Vue
181 lines
4.8 KiB
Vue
|
import addEventListenerWrap from '../../vc-util/Dom/addEventListener';
|
||
|
import type { EventHandler } from '../../_util/EventInterface';
|
||
|
import raf from '../../_util/raf';
|
||
|
import {
|
||
|
defineComponent,
|
||
|
onUnmounted,
|
||
|
nextTick,
|
||
|
watch,
|
||
|
computed,
|
||
|
ref,
|
||
|
watchEffect,
|
||
|
getCurrentInstance,
|
||
|
onMounted,
|
||
|
} from 'vue';
|
||
|
import type { PropType } from 'vue';
|
||
|
import devWarning from '../../vc-util/devWarning';
|
||
|
import type { ColumnType } from '../interface';
|
||
|
import { useInjectTableContext } from '../../table/context';
|
||
|
import supportsPassive from '../../_util/supportsPassive';
|
||
|
|
||
|
const events = {
|
||
|
mouse: {
|
||
|
start: 'mousedown',
|
||
|
move: 'mousemove',
|
||
|
stop: 'mouseup',
|
||
|
},
|
||
|
touch: {
|
||
|
start: 'touchstart',
|
||
|
move: 'touchmove',
|
||
|
stop: 'touchend',
|
||
|
},
|
||
|
};
|
||
|
type HandleEvent = MouseEvent & TouchEvent;
|
||
|
|
||
|
const defaultMinWidth = 50;
|
||
|
export default defineComponent({
|
||
|
name: 'DragHandle',
|
||
|
props: {
|
||
|
prefixCls: String,
|
||
|
width: {
|
||
|
type: Number,
|
||
|
required: true,
|
||
|
},
|
||
|
minWidth: {
|
||
|
type: Number,
|
||
|
default: defaultMinWidth,
|
||
|
},
|
||
|
maxWidth: {
|
||
|
type: Number,
|
||
|
default: Infinity,
|
||
|
},
|
||
|
column: {
|
||
|
type: Object as PropType<ColumnType<any>>,
|
||
|
default: undefined as ColumnType<any>,
|
||
|
},
|
||
|
},
|
||
|
setup(props) {
|
||
|
let startX = 0;
|
||
|
let moveEvent = { remove: () => {} };
|
||
|
let stopEvent = { remove: () => {} };
|
||
|
const removeEvents = () => {
|
||
|
moveEvent.remove();
|
||
|
stopEvent.remove();
|
||
|
};
|
||
|
onUnmounted(() => {
|
||
|
removeEvents();
|
||
|
});
|
||
|
watchEffect(() => {
|
||
|
devWarning(!isNaN(props.width), 'Table', 'width must be a number when use resizable');
|
||
|
});
|
||
|
|
||
|
const { onResizeColumn } = useInjectTableContext();
|
||
|
const minWidth = computed(() => {
|
||
|
return typeof props.minWidth === 'number' && !isNaN(props.minWidth)
|
||
|
? props.minWidth
|
||
|
: defaultMinWidth;
|
||
|
});
|
||
|
const maxWidth = computed(() => {
|
||
|
return typeof props.maxWidth === 'number' && !isNaN(props.maxWidth)
|
||
|
? props.maxWidth
|
||
|
: Infinity;
|
||
|
});
|
||
|
const instance = getCurrentInstance();
|
||
|
// eslint-disable-next-line vue/no-setup-props-destructure
|
||
|
let baseWidth = props.width;
|
||
|
onMounted(() => {
|
||
|
nextTick(() => {
|
||
|
baseWidth = instance.vnode.el?.parentNode?.getBoundingClientRect().width;
|
||
|
});
|
||
|
});
|
||
|
const dragging = ref(false);
|
||
|
let rafId: number;
|
||
|
const updateWidth = (e: HandleEvent) => {
|
||
|
let pageX = 0;
|
||
|
if (e.touches) {
|
||
|
if (e.touches.length) {
|
||
|
// touchmove
|
||
|
pageX = e.touches[0].pageX;
|
||
|
} else {
|
||
|
// touchend
|
||
|
pageX = e.changedTouches[0].pageX;
|
||
|
}
|
||
|
} else {
|
||
|
pageX = e.pageX;
|
||
|
}
|
||
|
const tmpDeltaX = startX - pageX;
|
||
|
let w = Math.max(baseWidth - tmpDeltaX, minWidth.value);
|
||
|
w = Math.min(w, maxWidth.value);
|
||
|
raf.cancel(rafId);
|
||
|
rafId = raf(() => {
|
||
|
onResizeColumn(w, props.column.__originColumn__);
|
||
|
});
|
||
|
};
|
||
|
const handleMove = (e: HandleEvent) => {
|
||
|
updateWidth(e);
|
||
|
};
|
||
|
const handleStop = (e: HandleEvent) => {
|
||
|
dragging.value = false;
|
||
|
updateWidth(e);
|
||
|
nextTick(() => {
|
||
|
baseWidth = instance.vnode.el?.parentNode?.getBoundingClientRect().width;
|
||
|
});
|
||
|
removeEvents();
|
||
|
};
|
||
|
const handleStart = (e: HandleEvent, eventsFor: any) => {
|
||
|
dragging.value = true;
|
||
|
removeEvents();
|
||
|
|
||
|
if (e instanceof MouseEvent && e.which !== 1) {
|
||
|
return;
|
||
|
}
|
||
|
if (e.stopPropagation) e.stopPropagation();
|
||
|
startX = e.touches ? e.touches[0].pageX : e.pageX;
|
||
|
moveEvent = addEventListenerWrap(document.documentElement, eventsFor.move, handleMove);
|
||
|
stopEvent = addEventListenerWrap(document.documentElement, eventsFor.stop, handleStop);
|
||
|
};
|
||
|
const handleDown: EventHandler = (e: HandleEvent) => {
|
||
|
e.stopPropagation();
|
||
|
e.preventDefault();
|
||
|
handleStart(e, events.mouse);
|
||
|
};
|
||
|
const handleTouchDown: EventHandler = (e: HandleEvent) => {
|
||
|
e.stopPropagation();
|
||
|
e.preventDefault();
|
||
|
handleStart(e, events.touch);
|
||
|
};
|
||
|
|
||
|
const handleClick: EventHandler = (e: HandleEvent) => {
|
||
|
e.stopPropagation();
|
||
|
e.preventDefault();
|
||
|
};
|
||
|
|
||
|
watch(
|
||
|
() => props.width,
|
||
|
() => {
|
||
|
if (!dragging.value) {
|
||
|
baseWidth = props.width;
|
||
|
}
|
||
|
},
|
||
|
{ immediate: true },
|
||
|
);
|
||
|
|
||
|
return () => {
|
||
|
const { prefixCls } = props;
|
||
|
const touchEvents = {
|
||
|
[supportsPassive ? 'onTouchstartPassive' : 'onTouchstart']: e => handleTouchDown(e),
|
||
|
};
|
||
|
return (
|
||
|
<div
|
||
|
class={`${prefixCls}-resize-handle ${dragging.value ? 'dragging' : ''}`}
|
||
|
onMousedown={handleDown}
|
||
|
{...touchEvents}
|
||
|
onClick={handleClick}
|
||
|
>
|
||
|
<div class={`${prefixCls}-resize-handle-line`}></div>
|
||
|
</div>
|
||
|
);
|
||
|
};
|
||
|
},
|
||
|
});
|