opt: 优化页面分割组件split功能和样式

This commit is contained in:
gary
2026-02-08 21:06:56 +08:00
parent 496bcf75ba
commit d7cbc2eebf

View File

@@ -1,6 +1,7 @@
<script setup> <script setup>
import { onMounted, onUnmounted, ref, useAttrs, watch } from 'vue' import { onMounted, ref, useAttrs, shallowRef, watch, computed } from 'vue'
import Split from 'split.js' import Split from 'split.js'
import { useElementSize } from '@vueuse/core'
/** /**
* 更多属性配置可以参考文档 * 更多属性配置可以参考文档
@@ -38,20 +39,31 @@ const props = defineProps({
default: false default: false
} }
}) })
const elementSizesRefs = ref([])
const itemRefs = ref([]) const itemRefs = ref([])
const isDragging = ref(false) const isDragging = ref(false)
const attrs = useAttrs() const attrs = useAttrs()
let splitInstance = null const splitInstance = shallowRef()
const initSplit = () => { const initSplit = () => {
if (splitInstance) { if (splitInstance.value) {
splitInstance.destroy() splitInstance.value.destroy()
splitInstance = null splitInstance.value = null
} }
// Clear previous size refs to avoid duplicates/leaks on re-init
elementSizesRefs.value = []
if (props.disabled) return if (props.disabled) return
splitInstance = Split(itemRefs.value.map(itemRef => itemRef), { const elements = itemRefs.value.filter(el => el)
if (elements.length === 0) return
splitInstance.value = Split(elements.map(itemRef => {
const { width, height } = useElementSize(itemRef)
elementSizesRefs.value.push(props.direction === 'vertical' ? height : width)
return itemRef
}), {
sizes: props.sizes, sizes: props.sizes,
minSize: props.minSize, minSize: props.minSize,
maxSize: props.maxSize, maxSize: props.maxSize,
@@ -59,23 +71,31 @@ const initSplit = () => {
gutterSize: 5, gutterSize: 5,
direction: props.direction, direction: props.direction,
...attrs, ...attrs,
gutter: (index, direction) => {
const gutter = document.createElement('div')
gutter.className = `gutter gutter-${direction}`
gutter.addEventListener('mousedown', () => {
gutter.classList.add('is-active')
})
return gutter
},
onDragStart: (sizes) => { onDragStart: (sizes) => {
isDragging.value = true isDragging.value = true
if (attrs.onDragStart) { if (attrs.onDragStart) {
attrs.onDragStart(sizes) attrs.onDragStart(sizes)
} }
if (props.onDragStart) {
props.onDragStart(sizes)
}
}, },
onDragEnd: (sizes) => { onDragEnd: (sizes) => {
isDragging.value = false isDragging.value = false
// remove is-active from all gutters
const container = itemRefs.value[0]?.parentNode
if (container) {
container.querySelectorAll('.gutter.is-active').forEach(el => el.classList.remove('is-active'))
}
if (attrs.onDragEnd) { if (attrs.onDragEnd) {
attrs.onDragEnd(sizes) attrs.onDragEnd(sizes)
} }
if (props.onDragEnd) {
props.onDragEnd(sizes)
}
} }
}) })
} }
@@ -84,27 +104,19 @@ onMounted(() => {
initSplit() initSplit()
}) })
onUnmounted(() => { watch(() => props.sizes, () => {
if (splitInstance) { initSplit()
splitInstance.destroy() }, { flush: 'post' })
}
})
watch(() => props.disabled, () => { watch(() => props.disabled, () => {
initSplit() initSplit()
}) }, { flush: 'post' })
watch(() => props.sizes, (newSizes) => { const elementSizes = computed(() => elementSizesRefs.value?.map(sizeRef => sizeRef.value))
if (splitInstance) {
splitInstance.setSizes(newSizes)
}
})
defineExpose({ defineExpose({
splitInstance, splitInstance,
getSizes: () => { elementSizes
return splitInstance ? splitInstance.getSizes() : props.sizes
}
}) })
</script> </script>
@@ -152,7 +164,7 @@ defineExpose({
background-position: 50%; background-position: 50%;
} }
/* Highlight when dragging (controlled by JS state) */ /* Highlight when dragging (controlled by JS state) */
.is-dragging > :deep(.gutter) { :deep(.gutter.is-active) {
background-color: #409eff !important; background-color: #409eff !important;
} }
</style> </style>