Files
ojnext/src/shared/Split/index.vue
2023-01-13 22:11:28 +08:00

142 lines
3.3 KiB
Vue

<template>
<div
:style="{ cursor, userSelect }"
class="vue-splitter-container clearfix"
@mouseup="onMouseUp"
@mousemove="onMouseMove"
>
<Pane
class="splitter-pane splitter-paneL"
:split="split"
:style="{ [type]: percent + '%' }"
>
<slot name="panel"></slot>
</Pane>
<Resizer
:className="className"
:style="{ [resizeType]: percent + '%' }"
:split="split"
@mousedown.native="onMouseDown"
@click.native="onClick"
></Resizer>
<Pane
class="splitter-pane splitter-paneR"
:split="split"
:style="{ [type]: 100 - percent + '%' }"
>
<slot name="paner"></slot>
</Pane>
<div class="vue-splitter-container-mask" v-if="active"></div>
</div>
</template>
<script setup lang="ts">
import Resizer from "./Resizer.vue"
import Pane from "./Pane.vue"
import { computed, ref } from "vue"
interface Props {
minPercent?: number
defaultPercent?: number
split: "vertical" | "horizontal"
className?: string
}
const props = withDefaults(defineProps<Props>(), {
minPercent: 10,
defaultPercent: 50,
split: "horizontal",
className: "",
})
const emit = defineEmits(["resize"])
const active = ref(false)
const hasMoved = ref(false)
const percent = ref(props.defaultPercent)
const type = ref(props.split === "vertical" ? "width" : "height")
const resizeType = ref(props.split === "vertical" ? "left" : "top")
const userSelect = computed(() => (active.value ? "none" : "auto"))
const cursor = computed(() =>
active.value ? (props.split === "vertical" ? "col-resize" : "row-resize") : ""
)
// watch(
// () => defaultPercent,
// (newValue) => {
// percent.value = newValue
// }
// )
function onClick() {
if (!hasMoved.value) {
percent.value = 50
emit("resize", percent.value)
}
}
function onMouseDown() {
active.value = true
hasMoved.value = false
}
function onMouseUp() {
active.value = false
}
function onMouseMove(e: any) {
if (e.buttons === 0) {
active.value = false
}
if (active.value) {
let offset = 0
let target = e.currentTarget
if (props.split === "vertical") {
while (target) {
offset += target.offsetLeft
target = target.offsetParent
}
} else {
while (target) {
offset += target.offsetTop
target = target.offsetParent
}
}
const currentPage = props.split === "vertical" ? e.pageX : e.pageY
const targetOffset =
props.split === "vertical"
? e.currentTarget.offsetWidth
: e.currentTarget.offsetHeight
const newPercent =
Math.floor(((currentPage - offset) / targetOffset) * 10000) / 100
if (newPercent > props.minPercent && newPercent < 100 - props.minPercent) {
percent.value = newPercent
}
emit("resize", newPercent)
hasMoved.value = true
}
}
</script>
<style scoped>
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.vue-splitter-container {
height: 100%;
position: relative;
}
.vue-splitter-container-mask {
z-index: 9999;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
</style>