基于vue3的splitter组件
基于vue2版(https://blog.csdn.net/losedguest/article/details/106281367)
修改如下(SpliterVbox.vue)
<template>
<div class="spliter-box" ref="spliterBox">
<div class="spliter-left" ref="spliterLeft" :style="{ width: leftWidth + 'px' }"
><slot name="leftBox"></slot
></div>
<div
class="spliter-line"
ref="spliterLine"
:style="{ left: leftWidth + 'px' }"
@mousedown.stop="ChangeLeftWith"
>
<i></i
><span
class="ico spliter-ico-left"
:class="{ 'spliter-ico-right': unexpand }"
@click.stop="ToggleExpand"
></span
></div>
<div
class="spliter-right"
ref="spliterRight"
:style="{ left: leftWidth + 10 + 'px', width: 'calc(100% - ' + (leftWidth + 10) + 'px)' }"
><slot name="rightBox"></slot
></div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
let oldLeftWidth = 200,
leftWidth = ref(200), // 左侧栏宽度
unexpand = ref(false), // 左侧栏是否折叠
MaxWidth = ref(0);
const spliterBox = ref(null);
const spliterLine = ref(null);
const spliterLeft = ref(null);
const spliterRight = ref(null);
onMounted(() => {
MaxWidth.value = spliterBox.value.clientWidth - spliterLine.value.offsetWidth;
});
function ToggleExpand() {
unexpand.value = !unexpand.value;
if (!unexpand.value) {
// 展开
leftWidth.value = oldLeftWidth; // 还原原始宽度
} else {
// 收起来
oldLeftWidth = leftWidth.value; // 记住原始的宽度
leftWidth.value = 0;
}
}
function ChangeLeftWith(e) {
let disX = (e || event).clientX; //鼠標起始橫向距離
let vleft = spliterLine.value.offsetLeft; //記錄起始的分割線的右邊距
document.onmousemove = function (e) {
let iT = vleft + ((e || event).clientX - disX); //分割線右邊距+移動距離
spliterLine.value.style.margin = 0;
iT < 0 && (iT = 0); //分割線超出左邊
iT > MaxWidth && (iT = MaxWidth.value); //分割線超出右邊
leftWidth.value = iT;
return false;
};
document.onmouseup = function () {
document.onmousemove = null;
document.onmouseup = null;
spliterLine.value.releaseCapture && spliterLine.value.releaseCapture();
};
spliterLine.value.setCapture && spliterLine.value.setCapture();
return false;
}
</script>
<style>
.spliter-box {
width: 100%;
height: 100%;
overflow: hidden;
}
.spliter-left {
position: absolute;
height: 100%;
overflow: hidden;
}
.spliter-right {
position: absolute;
height: 100%;
overflow: hidden;
}
.spliter-line {
position: absolute;
width: 6px;
height: 100%;
background-color: aliceblue;
cursor: col-resize;
border: 1px solid #00ffff;
overflow: hidden;
text-align: center;
display: table-cell;
vertical-align: middle;
}
.spliter-line i {
display: inline-block;
height: 100%;
vertical-align: middle;
}
.spliter-line span {
width: 6px;
height: 10px;
vertical-align: middle;
}
.spliter-ico-left {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAKCAYAAACXDi8zAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE0QTk1QTVBRTYwMTExRTdBRjQxOERENjkwQUFCMDI0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE0QTk1QTVCRTYwMTExRTdBRjQxOERENjkwQUFCMDI0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTRBOTVBNThFNjAxMTFFN0FGNDE4REQ2OTBBQUIwMjQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTRBOTVBNTlFNjAxMTFFN0FGNDE4REQ2OTBBQUIwMjQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz79g2URAAAAbElEQVR42mL8//8/AzJgjJv638dAgYEBJAHDDLFT/jOsf/kfRDMhq2QIDIHrZIILuruhGMkEFtTXYWD4+pWB4c8fVB3YANP/RdmMDBevMDBwczMwsLCg6gBL7tyFqgPGAEuuX4PwDy4PAgQYADcaMJfVpu88AAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position: center;
background-size: contain;
display: inline-block;
}
.spliter-ico-right {
transform: rotate(180deg);
-ms-transform: rotate(180deg); /* IE 9 */
-webkit-transform: rotate(180deg); /* Safari and Chrome */
}
.spliter-line .ico {
cursor: pointer;
}
</style>
使用方式不变
<template>
<div id="app">
<div style="width:400px;height:300px;margin-left:200px;border:1px solid;overflow:visible;position:relative;">
<SpliterVbox>
<template v-slot:leftBox>haha</template>
<template v-slot:rightBox>hehe</template>
</SpliterVbox>
</div>
</div>
</template>
<script>
import SpliterVbox from './components/SpliterVbox.vue'
</script>