You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

193 lines
6.2 KiB

<template>
<div class="split" ref="parent">
<slot></slot>
</div>
</template>
<script lang="ts">
//@ts-ignore
import Split from 'split.js'
import { defineComponent, onMounted, ref, type SetupContext, type VNode, watch } from 'vue'
interface IDataContainer {
instance: any;
elements: Array<any> | undefined;
sizes: Array<number> | undefined;
minSizes: Array<number> | undefined;
destroy: Function,
}
//@ts-ignore
export default defineComponent({
emits: ['onDrag', 'onDragStart', 'onDragEnd'],
props: {
direction: { type: String, default: 'horizontal' }, // vertical
gutterSize: { type: Number, default: 8 },
firstAreaDefaultSize: Number,
lastAreaDefaultSize: Number
},
setup(props, ctx: SetupContext) {
const parent = ref(null)
const dataVal = {
elements: new Array<any>(),
sizes: new Array<number>(),
minSizes: new Array<number>(),
instance: null,
//@ts-ignore
destory: Function
}
//@ts-ignore
const data = ref(dataVal as IDataContainer)
watch(() => props.direction, (value, oldValue) => {
init()
})
let useFirstDefaultSize = props.firstAreaDefaultSize && props.firstAreaDefaultSize > 0
let useLastDefaultSize = props.lastAreaDefaultSize && props.lastAreaDefaultSize > 0
let splitSumCount = 0
const refreshSize = (value) => {
if (data.value.instance) {
data.value.instance?.setSizes(value)
}
}
const init = () => {
if (data.value.instance !== null) {
data.value.instance?.destroy()
}
let splitCount = 0
data.value.instance = null
const splitOptions = {
direction: props.direction || 'horizontal',
sizes: data.value.sizes || 50,
minSize: data.value.minSizes || 100,
gutterSize: props.gutterSize || 8,
cursor: props.direction === 'horizontal' ? 'col-resize' : 'row-resize',
onDrag: function() {
useFirstDefaultSize = false
useLastDefaultSize = false
ctx.emit('onDrag', data.value.instance?.getSizes())
},
onDragStart: function() {
ctx.emit('onDragStart', data.value.instance?.getSizes())
},
onDragEnd: function() {
ctx.emit('onDragEnd', data.value.instance?.getSizes())
}
}
if (useFirstDefaultSize) {
splitOptions['elementStyle'] = function elementStyle(dimension, size, gutterSize) {
splitCount++
let res
if (splitSumCount === 2 && useFirstDefaultSize && !useLastDefaultSize) {
// 2个split-area & 使用firstAreaDefaultSize & 未使用lastAreaDefaultSize
if (splitCount === 1) {
res = { [dimension]: `calc(${props.firstAreaDefaultSize}px - ${gutterSize}px)` }
} else {
res = { [dimension]: `calc(100% - ${props.firstAreaDefaultSize + gutterSize}px)` }
}
} else if (splitSumCount === 2 && !useFirstDefaultSize && useLastDefaultSize) {
// 2个split-area & 未使用firstAreaDefaultSize & 使用了lastAreaDefaultSize
if (splitCount === 2) {
res = { [dimension]: `calc(${props.lastAreaDefaultSize}px - ${gutterSize}px)` }
} else {
res = { [dimension]: `calc(100% - ${props.lastAreaDefaultSize + gutterSize}px)` }
}
} else if (splitSumCount === 3 && useFirstDefaultSize && useLastDefaultSize) {
// 3个split-area & 使用firstAreaDefaultSize & 使用了lastAreaDefaultSize
if (splitCount === 1) {
res = { [dimension]: `calc(${props.firstAreaDefaultSize}px - ${gutterSize}px)` }
} else if (splitCount === 3) {
res = { [dimension]: `calc(${props.lastAreaDefaultSize}px - ${gutterSize}px)` }
} else {
res = { [dimension]: `calc(100% - ${props.firstAreaDefaultSize + props.lastAreaDefaultSize + gutterSize}px)` }
}
} else {
res = { [dimension]: `calc(${size}% - ${gutterSize}px)` }
}
return res
}
}
//@ts-ignore
data.value.instance = Split(data.value.elements ?? [],
splitOptions as Split.Options
)
}
onMounted(() => {
data.value.elements = []
data.value.sizes = []
data.value.minSizes = []
var parentVal = parent.value as unknown as HTMLElement
if (parentVal) {
for (var i = 0; i < parentVal.children.length; i++) {
var child = parentVal.children[i]
data.value.elements.push(child)
}
}
if (ctx.slots.default) {
ctx.slots.default()?.forEach((vnode: VNode) => {
const vodeType = vnode.type as any
if (vodeType.name == 'SplitArea') {
if (vnode.props) {
const a = vnode.props as {
size: number;
minSize: number;
}
data.value.sizes?.push(a.size)
data.value.minSizes?.push(a.minSize)
}
}
})
splitSumCount = ctx.slots.default().length
}
init()
})
const reset = () => {
useFirstDefaultSize = props.firstAreaDefaultSize && props.firstAreaDefaultSize > 0
useLastDefaultSize = props.lastAreaDefaultSize && props.lastAreaDefaultSize > 0
init()
}
const getSizes = () => {
return data.value.instance?.getSizes() || 0
}
return { data, init, parent, reset, getSizes, refreshSize }
}
})
</script>
<style>
.split {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
height: 100%;
width: 100%;
}
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}
.gutter.gutter-horizontal {
cursor: col-resize;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==");
}
.gutter.gutter-vertical {
cursor: row-resize;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFAQMAAABo7865AAAABlBMVEVHcEzMzMzyAv2sAAAAAXRSTlMAQObYZgAAABBJREFUeF5jOAMEEAIEEFwAn3kMwcB6I2AAAAAASUVORK5CYII=");
}
.split.split-horizontal,
.gutter.gutter-horizontal {
height: 100%;
float: left;
}
</style>