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
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>
|