-
- <div class="split" :class="{ horizontal }">
- <div class="sub" ref="one" :style="{ flexGrow: grow1 }">
- <slot name="one">slot>
- div>
- <div class="resizer" @mousedown="startResize">div>
- <div class="sub" ref="two" :style="{ flexGrow: grow2 }">
- <slot name="two">slot>
- div>
- div>
-
- <script setup>
- import { ref } from "vue";
- const props = defineProps({
- horizontal: Boolean,
- ratio: String,
- });
-
- const one = ref(null);
- const two = ref(null);
-
-
- // methods
- function parseRatio(ratio) {
- // ratio: strings like "1/2"
- const rn = ratio
- ?.split("/")
- ?.map(Number)
- ?.filter((val) => !isNaN(val));
-
- if (!rn || rn.length !== 2) {
- return [1, 1];
- }
-
- return rn;
- }
-
- const [initGrow1, initGrow2] = parseRatio(props.ratio); // 分屏占比
-
- // states
- const grow1 = ref(initGrow1);
- const grow2 = ref(initGrow2);
- function startResize(mde) {
- one.value?.classList.add("forbid-select");
- two.value?.classList.add("forbid-select");
-
- const initialPos = props.horizontal ? mde.clientY : mde?.clientX;
- const sizeOne = props.horizontal
- ? one?.value?.offsetHeight
- : one?.value?.offsetWidth;
- const sizeTwo = props.horizontal
- ? two?.value?.offsetHeight
- : two?.value?.offsetWidth;
-
- function handleMouseMove(mme) {
- // forbid select
-
- let pos = props.horizontal ? mme.clientY : mme?.clientX;
- let newSizeOne = sizeOne + pos - initialPos;
-
- const totalGrow = grow1.value + grow2.value;
- grow1.value = totalGrow * (newSizeOne / (sizeOne + sizeTwo));
- grow2.value = totalGrow - grow1.value;
- }
-
- function handleMouseUp(mue) {
- one.value?.classList.remove("forbid-select");
- two.value?.classList.remove("forbid-select");
-
- document.removeEventListener("mousemove", handleMouseMove);
- document.removeEventListener("mouseup", handleMouseUp);
- }
-
- document.addEventListener("mousemove", handleMouseMove);
- document.addEventListener("mouseup", handleMouseUp);
- }
- script>
-
- <style scoped>
- .forbid-select {
- -moz-user-select: none;
- -webkit-user-select: none;
- -ms-user-select: none;
- user-select: none;
- }
-
- .split {
- width: 100%;
- height: 100%;
- display: flex;
- }
-
- .split .resizer {
- width: 6px;
- cursor: w-resize;
- transition: 0.3s;
- }
-
- .split .resizer:hover {
- background-color: #dee5f3;
- }
-
- .split .sub {
- width: 100%;
- height: 100%;
- flex-grow: 1;
- flex-basis: 0%;
- align-items: stretch;
- align-content: stretch;
-
- overflow-y: auto;
- overflow-x: hidden;
- scrollbar-width: thin;
- }
-
- .split .sub::-webkit-scrollbar {
- width: 8px;
- }
-
- .split .sub::-webkit-scrollbar-track {
- background-color: #fff;
- }
-
- .split .sub::-webkit-scrollbar-thumb {
- background-color: #666;
- }
-
- .split .horizontal {
- flex-direction: column;
- }
-
- .split .horizontal .resizer {
- height: 5px;
- width: 100%;
- cursor: n-resize;
- }
- style>
示例 二分屏
- <splitScreen ratio="1/2">
- <template #one>
- <div>onediv>
- template>
-
- <template #two>
- <div>twodiv>
- template>
- splitScreen>
三分屏
- <splitScreen ratio="1/2">
- <template #one>
- <div>onediv>
- template>
-
- <template #two>
- <splitScreen ratio="3/2">
- <template #one>
- <div>onediv>
- template>
-
- <template #two>
- <div>twodiv>
- template>
- splitScreen>
- template>
- splitScreen>