개요[ | ]
- TheSplit.vue
html
Copy
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useResizeObserver, useEventListener } from '@vueuse/core';
const props = defineProps<{
direction: 'horizontal' | 'vertical';
initialPercentage?: number;
}>();
const container = ref<HTMLElement | null>(null);
const divider = ref<HTMLElement | null>(null);
const firstPanePercentage = ref(props.initialPercentage ?? 50);
const isResizing = ref(false);
const MIN_SIZE = 100;
const isVertical = computed(() => props.direction === 'vertical');
const adjustSizes = (containerSize: number) => {
const minPercentage = (MIN_SIZE / containerSize) * 100;
const maxPercentage = 100 - minPercentage;
firstPanePercentage.value = Math.max(minPercentage, Math.min(maxPercentage, firstPanePercentage.value));
};
useResizeObserver(container, (entries) => {
const { width, height } = entries[0].contentRect;
adjustSizes(isVertical.value ? height : width);
});
const disableIframes = () => {
document.querySelectorAll('iframe').forEach((iframe) => {
iframe.style.pointerEvents = 'none';
});
};
const enableIframes = () => {
document.querySelectorAll('iframe').forEach((iframe) => {
iframe.style.pointerEvents = 'auto';
});
};
const handleMouseMove = (e: MouseEvent) => {
if (!isResizing.value || !container.value) return;
const rect = container.value.getBoundingClientRect();
const containerSize = isVertical.value ? rect.width : rect.height;
const mousePosition = isVertical.value ? e.clientX - rect.left : e.clientY - rect.top;
const newPercentage = (mousePosition / containerSize) * 100;
const minPercentage = (MIN_SIZE / containerSize) * 100;
const maxPercentage = 100 - minPercentage;
firstPanePercentage.value = Math.max(minPercentage, Math.min(maxPercentage, newPercentage));
};
const stopResize = () => {
document.body.style.userSelect = '';
isResizing.value = false;
enableIframes();
};
const startResize = () => {
document.body.style.userSelect = 'none';
isResizing.value = true;
disableIframes();
};
useEventListener(window, 'mousemove', handleMouseMove);
useEventListener(window, 'mouseup', stopResize);
onMounted(() => {
if (container.value) {
firstPanePercentage.value = props.initialPercentage ?? 50;
}
});
</script>
<template>
<div ref="container" :class="['relative w-full h-full flex', isVertical ? 'flex-row' : 'flex-col']">
<div class="overflow-auto" :style="{ flex: `0 0 ${firstPanePercentage}%` }">
<slot name="first"></slot>
</div>
<div ref="divider"
:class="['relative z-10 bg-gray-200 dark:bg-gray-800 divider', isVertical ? 'w-2 h-full cursor-ew-resize' : 'h-2 w-full cursor-ns-resize']"
@mousedown="startResize">
</div>
<div class="overflow-auto flex-1">
<slot name="second"></slot>
</div>
</div>
</template>
편집자 Jmnote
로그인하시면 댓글을 쓸 수 있습니다.