
第一个版本如下
<template>
<div class="split-panel-container">
<div class="panel-left" :style="{ width: `${leftWidth}%` }">
<div class="panel-content" v-bind:style="isResizing ? noSelectStyle : {}">
<slot name="left">
<div class="default-content">左侧面板内容</div>
</slot>
</div>
</div>
<div class="resize-handle" @mousedown="startResize">
<div class="handle-icon"></div>
</div>
<div class="panel-right" :style="{ width: `${rightWidth}%` }">
<div class="panel-content" v-bind:style="isResizing ? noSelectStyle : {}">
<slot name="right">
<div class="default-content">右侧面板内容</div>
</slot>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'
const props = defineProps({
defaultLeftWidth: {
type: Number,
default: 70
},
minLeftWidth: {
type: Number,
default: 30
},
minRightWidth: {
type: Number,
default: 20
}
})
const leftWidth = ref(props.defaultLeftWidth)
const rightWidth = ref(100 - props.defaultLeftWidth)
const isResizing = ref(false)
// 禁止选择样式
const noSelectStyle = computed(() => ({
'user-select': 'none',
'-webkit-user-select': 'none',
'pointer-events': 'none'
}))
const startResize = (e: MouseEvent) => {
isResizing.value = true
document.body.style.cursor = 'col-resize'
document.addEventListener('mousemove', handleResize)
document.addEventListener('mouseup', stopResize)
e.preventDefault() // 阻止默认行为,防止选中内容
}
const handleResize = (e: MouseEvent) => {
if (!isResizing.value) return
const container = document.querySelector('.split-panel-container') as HTMLElement
const containerRect = container.getBoundingClientRect()
const containerWidth = containerRect.width
// 计算鼠标在容器中的相对位置百分比
let mouseX = e.clientX - containerRect.left
let newLeftWidth = (mouseX / containerWidth) * 100
// 应用最小宽度限制
if (newLeftWidth < props.minLeftWidth) newLeftWidth = props.minLeftWidth
if (newLeftWidth > 100 - props.minRightWidth) newLeftWidth = 100 - props.minRightWidth
leftWidth.value = newLeftWidth
rightWidth.value = 100 - newLeftWidth
}
const stopResize = () => {
isResizing.value = false
document.body.style.cursor = ''
document.removeEventListener('mousemove', handleResize)
document.removeEventListener('mouseup', stopResize)
}
onMounted(() => {
// 初始化宽度
leftWidth.value = props.defaultLeftWidth
rightWidth.value = 100 - props.defaultLeftWidth
})
onUnmounted(() => {
document.removeEventListener('mousemove', handleResize)
document.removeEventListener('mouseup', stopResize)
})
</script>
<style scoped lang="scss">
.split-panel-container {
display: flex;
width: 100%;
height: 100%;
min-height: 300px;
overflow: hidden;
.panel-left, .panel-right {
position: relative;
overflow: auto;
transition: width 0.1s ease;
/* 自定义滚动条 */
&::-webkit-scrollbar {
width: 8px;
height: 8px;
}
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-thumb {
background: rgba(150, 150, 150, 0.5);
border-radius: 4px;
transition: background 0.2s;
}
&::-webkit-scrollbar-thumb:hover {
background: rgba(100, 100, 100, 0.7);
}
}
.panel-left {
/* 关键调整:将左侧面板的右侧padding设置为负数,使内容可以扩展到滚动条区域 */
padding-right: -8px;
margin-right: 8px; /* 补偿padding,保持整体宽度不变 */
/* 让左侧面板的滚动条与分割线重叠 */
&::-webkit-scrollbar {
position: absolute;
right: 0;
width: 8px; /* 滚动条宽度 */
}
}
.resize-handle {
position: relative;
width: 6px;
background-color: #f0f0f0;
cursor: col-resize;
border-left: 1px solid #ddd;
border-right: 1px solid #ddd;
z-index: 20; /* 确保分割线在最上层 */
/* 鼠标悬停和拖动时的样式 */
&:hover, &:active {
background-color: #e0e0e0;
}
.handle-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 2px;
height: 30px;
background-color: #ccc;
&::before, &::after {
content: '';
position: absolute;
width: 2px;
height: 30px;
background-color: #ccc;
}
&::before {
left: -6px;
}
&::after {
left: 6px;
}
}
}
.panel-content {
padding: 16px;
min-height: 100%;
}
.default-content {
padding: 20px;
background-color: #f9f9f9;
border-radius: 4px;
margin: 10px;
}
}
</style>
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)
评价
排名
8
文章
252
粉丝
7
评论
7
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:
50010702506256


欢迎加群交流技术